fix(strategy): gate checkpoint_remote bootstrap fetch to explicit enable flow · Entire

fix(strategy): gate checkpoint_remote bootstrap fetch to explicit enable flow

df72c4f→main·

suhaanthayyil·6d ago·3 files·+160 added/-3 removed

EnsurePrimaryRef's bootstrapPrimaryFromCheckpointRemote runs a network fetch (up to 30s) when the local primary metadata ref is missing and not fetchable from origin. EnsureSetup, which calls EnsurePrimaryRef, executes synchronously on every TurnStart hook — so a slow or unreachable checkpoint_remote could stall the hot hook path (hooks are killed at 30s) before the empty-orphan fallback ever ran, repeating the expensive fetch on every subsequent turn instead of self-healing once.

Gate the bootstrap fetch behind a new WithCheckpointRemoteBootstrap context marker, set only by the explicit entire enable / agent-setup flows in setup.go. The per-turn hook path (lifecycle.go) no longer opts in, so it stays network-free and falls back to the empty orphan immediately when the local ref is missing.

Changes

3

1255 unmodified lines

1256
1257
1258
1259
1259
1260
1261
1262
1263
1264
1265
1266
483 unmodified lines

1750
1751
1752
1749
1753
1754
1755
1756
1757
1758
1759
1760

1255 unmodified lines

return fmt.Errorf("failed to save settings: %w", err)
}

if err := strategy.EnsureSetup(ctx); err != nil {
    // Explicit, user-initiated setup: allow EnsurePrimaryRef to fetch a
    // missing primary metadata ref from a configured checkpoint_remote
    // (bootstrapPrimaryFromCheckpointRemote is otherwise a no-op — see
    // strategy.WithCheckpointRemoteBootstrap).
    if err := strategy.EnsureSetup(strategy.WithCheckpointRemoteBootstrap(ctx)); err != nil {
        return fmt.Errorf("failed to setup strategy: %w", err)
    }
}

483 unmodified lines

return err
}

if err := strategy.EnsureSetup(ctx); err != nil {
    // Explicit, user-initiated setup: allow EnsurePrimaryRef to fetch a
    // missing primary metadata ref from a configured checkpoint_remote
    // (bootstrapPrimaryFromCheckpointRemote is otherwise a no-op — see
    // strategy.WithCheckpointRemoteBootstrap).
    if err := strategy.EnsureSetup(strategy.WithCheckpointRemoteBootstrap(ctx)); err != nil {
        return fmt.Errorf("failed to setup strategy: %w", err)
    }
}

Mcmd/entire/cli/setup.go+10/-2

12 unmodified lines

13
14
15
16
17
18
19
905 unmodified lines

925
926
927
927
928
929
930
931
932
933
934
935
7 unmodified lines

943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058

12 unmodified lines

"github.com/entireio/cli/cmd/entire/cli/paths"
    "github.com/entireio/cli/cmd/entire/cli/testutil"

"github.com/go-git/go-git/v6/plumbing"
    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/require"
)
905 unmodified lines

require.NoError(t, err)
    defer repo.Close()

require.NoError(t, EnsurePrimaryRef(ctx, repo))
    // Only an explicit setup flow (WithCheckpointRemoteBootstrap) is allowed
    // to fetch from the checkpoint remote here — see
    // TestEnsurePrimaryRef_SkipsCheckpointRemoteBootstrapOutsideEnableFlow for
    // the per-turn hot-path behavior.
    require.NoError(t, EnsurePrimaryRef(WithCheckpointRemoteBootstrap(ctx), repo))

// The local metadata branch must now match the checkpoint remote's tip,
    // not a fresh empty orphan.
7 unmodified lines

"the bootstrapped branch should contain the checkpoint committed on the remote")
}

// TestEnsurePrimaryRef_SkipsCheckpointRemoteBootstrapOutsideEnableFlow verifies
// that EnsurePrimaryRef never fetches from a configured checkpoint_remote
// unless the caller explicitly opts in via WithCheckpointRemoteBootstrap. This
// models the per-turn hook hot path (EnsureSetup runs synchronously on every
// TurnStart hook, which has a hard execution timeout): steady-state must stay
// network-free even when a checkpoint_remote with real data is configured.
func TestEnsurePrimaryRef_SkipsCheckpointRemoteBootstrapOutsideEnableFlow(t *testing.T) {
    ctx := context.Background()

// Checkpoint remote: a repo that already holds entire/checkpoints/v1 with a
    // real (non-empty) commit — models the branch created on device A.
    remoteDir := t.TempDir()
    testutil.InitRepo(t, remoteDir)
    testutil.WriteFile(t, remoteDir, "f.txt", "init")
    testutil.GitAdd(t, remoteDir, "f.txt")
    testutil.GitCommit(t, remoteDir, "init")
    remoteDefaultBranch := checkpointRemoteCurrentBranch(ctx, t, remoteDir)

runCheckpointRemoteGit(ctx, t, remoteDir, "checkout", "--orphan", paths.MetadataBranchName)
    runCheckpointRemoteGit(ctx, t, remoteDir, "rm", "-rf", ".")
    commitCheckpointRemoteMetadata(ctx, t, remoteDir, "aaaaaaaaaaaa", "device-a")
    runCheckpointRemoteGit(ctx, t, remoteDir, "checkout", remoteDefaultBranch)

// Local repo: origin points at the main repo and a separate
    // checkpoint_remote is configured; the local metadata branch does not exist.
    localDir := t.TempDir()
    testutil.InitRepo(t, localDir)
    testutil.WriteFile(t, localDir, "f.txt", "init")
    testutil.GitAdd(t, localDir, "f.txt")
    testutil.GitCommit(t, localDir, "init")
    runCheckpointRemoteGit(ctx, t, localDir, "remote", "add", "origin", "git@github.com:org/main-repo.git")

entireDir := filepath.Join(localDir, ".entire")
    require.NoError(t, os.MkdirAll(entireDir, 0o755))
    require.NoError(t, os.WriteFile(
        filepath.Join(entireDir, "settings.json"),
        []byte(`{"enabled": true, "strategy_options": {"checkpoint_remote": {"provider": "github", "repo": "org/checkpoints"}}}`),
        0o644,
    ))

// Redirect the derived checkpoint_remote URL to the local file:// remote.
    // If EnsurePrimaryRef were to fetch here, this hermetic redirect would let
    // it succeed — so a passing test proves the fetch was skipped, not merely
    // that it failed silently.

edirectGitURL(t, localDir, "git@github.com:org/checkpoints.git", "file://"+remoteDir)

...
}

// TestEnsurePrimaryRef_OfflineCheckpointRemoteFallsBackToOrphan verifies that
// even in an explicit setup flow (WithCheckpointRemoteBootstrap), an
// unreachable checkpoint_remote does not fail EnsurePrimaryRef or hang the
// caller — it must fall back to creating the empty orphan, matching the
// pre-existing offline/no-remote behavior.
func TestEnsurePrimaryRef_OfflineCheckpointRemoteFallsBackToOrphan(t *testing.T) {
    ctx := context.Background()

localDir := t.TempDir()
    testutil.InitRepo(t, localDir)
    testutil.WriteFile(t, localDir, "f.txt", "init")
    testutil.GitAdd(t, localDir, "f.txt")
    testutil.GitCommit(t, localDir, "init")
    runCheckpointRemoteGit(ctx, t, localDir, "remote", "add", "origin", "git@github.com:org/main-repo.git")

// Redirect the derived checkpoint_remote URL to a nonexistent local path
    // so the fetch fails fast (no network access, no hang) rather than
    // exercising the real 30s timeout.
    redirectGitURL(t, localDir, "git@github.com:org/checkpoints.git", "file:///nonexistent/checkpoints.git")

...
}