# test(integration): real-hook push A-group (A1-A4, A6 queue drain)

`4b577de`·  
  
Soph·1w ago·2 files·+271 added/-7 removed

Exercise the git-invoked pre-push hook end to end for both checkpoint backends, closing the "real hook is never asserted" blind spot from the git-remote test plan.

- A1: extend the seed test to assert the user branch itself arrives (the user push is unaffected by the checkpoint sync).
- A2: a push carrying only a non-checkpointed commit is a fast no-op (RemoteCheckpointState digest unchanged).
- A3: `git push --delete` (zero-sha stdin) and a tag-only push run through the real hook without crashing and exit 0.
- A4: checkpoints routed to a genuinely unreachable target (a missing repo on the in-process HTTPS server) degrade gracefully; the user push still lands the feature branch. Local-path origins can't express this (URL derivation falls back to origin), hence the HTTPS setup.
- A6 (git-refs slice): a real push drains the per-checkpoint push queue; the v1 alternates rebase scenario has no git-refs equivalent.

Adds GitPushArgsWithHooks, GitTag, PushQueueRefs, and SetGitConfig helpers.

## Sessions

0d5ed27f5bb0View transcript

## Changes

2

- cmd/entire/cli/integration_test

- Mreal_hook_push_test.go+194/-7

- Mtestenv.go+77

```go
// TestGitPushWithHooks_SyncsCheckpointsToRemote is the seed of test A1: a plain
// `git push` of a feature branch, running the installed pre-push hook exactly as
// git runs it (realistic stdin refspecs, remote name/URL argv), lands the
// committed checkpoints on the bare remote WITHOUT any explicit RunPrePush or
// PushCheckpointRefs. It runs under both checkpoint backends via ForEachBackend,
// validating the whole I-1/I-2 enabler stack: env injection selects the store,
// the real hook drains it, and the backend-aware assertion finds the result.
func TestGitPushWithHooks_SyncsCheckpointsToRemote(t *testing.T) {
	t.Parallel()

if !env.CheckpointExistsOnRemote(bareDir, checkpointID) {
		t.Fatalf("[%s] checkpoint %s should be on remote after `git push` via the real pre-push hook", backend, checkpointID)
	}

// The user's own push is unaffected: the feature branch itself arrives on
	// the remote alongside the checkpoints.
	if !env.BranchExistsOnRemote(bareDir, "feature/test-branch") {
		t.Fatalf("[%s] user feature branch should arrive on remote via the same push", backend)
	}
}

// TestGitPushWithHooks_NoNewCheckpointsIsNoOp is test A2: once checkpoints are
// synced, a later push carrying only a plain (non-checkpointed) commit runs the
// real hook, but with nothing new to push the remote checkpoint state is
// byte-for-byte unchanged and the user push still succeeds.
func TestGitPushWithHooks_NoNewCheckpointsIsNoOp(t *testing.T) {
	t.Parallel()

ForEachBackend(t, func(t *testing.T, backend string) {
		env := NewFeatureBranchEnv(t)
		env.CheckpointStore = backend

bareDir := env.SetupBareRemote()

// First push syncs the checkpoint to the remote.
		_ = createCheckpointedCommit(t, env, "Add auth module", "auth.go", "package auth", "Add auth module")
		env.GitPushWithHooks("origin", "HEAD")
		if !env.CheckpointsPresentOnRemote(bareDir) {
			t.Fatalf("[%s] checkpoints should be on remote after the first push", backend)
		}

stateBefore := env.RemoteCheckpointState(bareDir)

// A plain commit with no session activity, then push again through the real
		// hook. The hook runs but finds nothing new to sync.
		env.WriteFile("README.md", "# updated")
		env.GitAdd("README.md")
		env.GitCommit("Docs tweak (no session)")
		env.GitPushWithHooks("origin", "HEAD")

stateAfter := env.RemoteCheckpointState(bareDir)
		if stateBefore != stateAfter {
			t.Errorf("[%s] remote checkpoint state should be unchanged by a push with no new checkpoints:\nbefore=%s\nafter=%s",
				backend, stateBefore, stateAfter)
		}
	})
}

// TestGitPushWithHooks_DeleteAndTagPushesAreNoOp is test A3: a branch deletion
// (`git push --delete`, whose stdin carries a zero-sha line) and a tag-only push
// run through the real pre-push hook without crashing and exit 0. With no local
// checkpoints there is nothing to sync, so the remote checkpoint state stays
// empty — the unusual push shapes don't trigger a spurious checkpoint push.
func TestGitPushWithHooks_DeleteAndTagPushesAreNoOp(t *testing.T) {
	t.Parallel()

ForEachBackend(t, func(t *testing.T, backend string) {
		env := NewFeatureBranchEnv(t)
		env.CheckpointStore = backend

bareDir := env.SetupBareRemote()

// Seed a throwaway branch and a tag on the remote (setup plumbing, hook
		// bypassed) so we have something to delete and a tag to push.
		env.GitCheckoutNewBranch("to-delete")
		env.WriteFile("scratch.txt", "scratch")
		env.GitAdd("scratch.txt")
		env.GitCommit("scratch commit")
		env.GitPush("origin", "to-delete")
		env.GitCheckoutNewBranch("feature/back")

// Branch delete through the real hook — stdin carries a zero-sha refspec.
		out, err := env.GitPushArgsWithHooks("origin", "--delete", "to-delete")
		if err != nil {
			t.Fatalf("[%s] `git push --delete` via the real hook should exit 0, got: %v\n%s", backend, err, out)
		}

// Tag-only push through the real hook — stdin carries a tag refspec.
		tagName := "v0.0.1"
		env.GitTag(tagName)
		out, err = env.GitPushArgsWithHooks("origin", "refs/tags/" + tagName)
		if err != nil {
			t.Fatalf("[%s] tag-only push via the real hook should exit 0, got: %v\n%s", backend, err, out)
		}

// No sessions ran, so no checkpoint push should have been attempted.
		if env.CheckpointsPresentOnRemote(bareDir) {
			t.Errorf("[%s] no checkpoints should be on remote after delete/tag pushes (none were created)", backend)
		}
	})
}

// TestGitPushWithHooks_UnreachableCheckpointRemoteContinues is test A4, the
// real-hook variant of graceful degradation: when checkpoints are routed to a
// genuinely unreachable target, the user's push must still succeed.

// A local-path origin can't express this — checkpoint_remote URL derivation fails
// on a file path and silently falls back to origin (which is reachable). So this
// runs over the in-process HTTPS server: origin is the (existing) main-repo, while
// checkpoint_remote points at a sibling repo that does NOT exist on the server.
// The CLI's checkpoint push (token-authenticated) fails at the missing repo and
// degrades gracefully; the user's own push, authenticated via credentials
// embedded in the origin URL, lands the feature branch on main-repo.
func TestGitPushWithHooks_UnreachableCheckpointRemoteContinues(t *testing.T) {
	t.Parallel()

ForEachBackend(t, func(t *testing.T, backend string) {
		srv := startGitHTTPSServer(t, "testorg/main-repo")
		env := NewFeatureBranchEnv(t)
		env.CheckpointStore = backend

mainBare := srv.BareDirs["testorg/main-repo"]

// Seed main-repo over the file path, then point origin at the plain HTTPS
		// URL. The go-git backend requires a non-empty Authorization header for
		// receive-pack; real git only sends one after a challenge, so set a static
		// http.extraHeader that git sends proactively on every request.
		httpsURL := srv.URL + "/testorg/main-repo.git"
		seedBareRepo(t, env, mainBare, httpsURL)
		env.SetGitConfig("http.extraHeader", "Authorization: Basic dGVzdDp0ZXN0")

// checkpoint_remote points at a repo that does not exist on the server.
		env.PatchSettings(map[string]any{
			"strategy_options": map[string]any{
				"checkpoint_remote": map[string]any{
					"provider": "github",
					"repo": "testorg/does-not-exist",
				},
			},
		})
		env.ExtraEnv = srv.tokenEnv("a4-token")

_ = createCheckpointedCommit(t, env, "Add module", "mod.go", "package mod", "Add module")
		if !env.CheckpointsPresentLocally() {
			t.Fatalf("[%s] should have local checkpoints after condensation", backend)
		}

out, err := env.GitPushArgsWithHooks("origin", "HEAD")
		if err != nil {
			t.Fatalf("[%s] user push should succeed even when the checkpoint remote is unreachable, got: %v\n%s", backend, err, out)
		}

if !env.BranchExistsOnRemote(mainBare, "feature/test-branch") {
			t.Errorf("[%s] user feature branch should land on origin (main-repo)", backend)
		}
		// Checkpoints were routed to the missing sibling repo, so nothing landed
		// on main-repo.
		if env.CheckpointsPresentOnRemote(mainBare) {
			t.Errorf("[%s] checkpoints should NOT land on main-repo when routed to a missing checkpoint_remote", backend)
		}
	})
}

// TestGitPushWithHooks_GitRefsDrainsPushQueue is the git-refs slice of A6: a real
// `git push` drains the per-checkpoint push queue that git-refs writes on each
// checkpoint. After the hook-driven push the ref is on the bare remote and the
// queue file (in the git common dir) is emptied, proving the hook consumed the
// queue rather than leaving entries to accumulate.
func TestGitPushWithHooks_GitRefsDrainsPushQueue(t *testing.T) {
	t.Parallel()

env := NewFeatureBranchEnv(t)
	env.CheckpointStore = StoreGitRefs

bareDir := env.SetupBareRemote()

checkpointID := createCheckpointedCommit(t, env, "Add service", "svc.go", "package svc", "Add service")
	if checkpointID == "" {
		t.Fatal("should have a checkpoint ID after condensation")
	}

// The checkpoint write enqueued its ref for push.
	if got := env.PushQueueRefs(); len(got) == 0 {
		t.Fatal("git-refs: push queue should hold the new checkpoint ref before push")
	}

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

if !env.CheckpointExistsOnRemote(bareDir, checkpointID) {
		t.Fatalf("git-refs: checkpoint %s should be on remote after the hook-driven push", checkpointID)
	}
	if got := env.PushQueueRefs(); len(got) != 0 {
		t.Errorf("git-refs: push queue should be drained after a successful push, still holds: %v", got)
	}
}
```
