package dispatcher

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/desktop/internal/agent"
	"github.com/tidbcloud/AgentTeam/desktop/internal/agent/runtimeconfig"
	"github.com/tidbcloud/AgentTeam/desktop/internal/consts"
	"github.com/tidbcloud/AgentTeam/desktop/internal/metrics"
	"github.com/tidbcloud/AgentTeam/desktop/internal/promptcompiler"
	"github.com/tidbcloud/AgentTeam/desktop/internal/types"
)

func testResolvedInstructions() resolvedInstructionContext {
	return resolvedInstructionContext{
		skillDocParts: types.SkillDocParts{
			Core:      "Core rules",
			Reference: "## Channel Reference\n\nUse AgentTeam tools.",
		},
	}
}

func TestExtensionGuidanceChangesSessionFingerprintWithoutCredentialMaterial(t *testing.T) {
	agentConfig := agent.Config{ID: "agent-1", Name: "reviewer"}
	binding := conversationBinding{
		channelID: "server-1", targetScopeType: "channel", targetID: "#agentteam",
	}
	base := resolvedInstructionContext{}
	first := base
	first.extension = promptcompiler.ExtensionCompileInput{
		Enabled:  true,
		Guidance: promptcompiler.ExtensionCatalogGuidanceTemplateData{Actions: []promptcompiler.ExtensionCatalogGuidanceAction{{ExtensionName: "github", ActionName: "list"}}},
	}
	sameScopeAfterTokenRotation := first
	second := base
	second.extension = promptcompiler.ExtensionCompileInput{
		Enabled:  true,
		Guidance: promptcompiler.ExtensionCatalogGuidanceTemplateData{Actions: []promptcompiler.ExtensionCatalogGuidanceAction{{ExtensionName: "github", ActionName: "create"}}},
	}

	firstFingerprint, err := compileSessionInstructionsFingerprint(
		t.TempDir(),
		agentConfig,
		runtimeconfig.TypeCodex,
		binding,
		types.InboxMessage{},
		first,
		nil,
		true,
	)
	require.NoError(t, err)
	rotatedFingerprint, err := compileSessionInstructionsFingerprint(
		t.TempDir(),
		agentConfig,
		runtimeconfig.TypeCodex,
		binding,
		types.InboxMessage{},
		sameScopeAfterTokenRotation,
		nil,
		true,
	)
	require.NoError(t, err)
	secondFingerprint, err := compileSessionInstructionsFingerprint(
		t.TempDir(),
		agentConfig,
		runtimeconfig.TypeCodex,
		binding,
		types.InboxMessage{},
		second,
		nil,
		true,
	)
	require.NoError(t, err)

	require.NotEmpty(t, firstFingerprint)
	require.Equal(t, firstFingerprint, rotatedFingerprint)
	require.NotEqual(t, firstFingerprint, secondFingerprint)
}

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

	baseAgent := agent.Config{
		ID:          "agent-1",
		Name:        "reviewer",
		Description: "Review the queue and respond precisely.",
	}
	baseBinding := conversationBinding{
		channelID:       "channel-1",
		targetScopeType: "channel",
		targetID:        "thread:alpha",
	}
	skillDocParts := types.SkillDocParts{
		Core:      "Core rules",
		Reference: "Reference material",
	}

	tests := []struct {
		name    string
		binding conversationBinding
		msg     types.InboxMessage
		want    []types.TrajectoryEntry
	}{
		{
			name:    "fresh start emits contract plus fresh turn input",
			binding: baseBinding,
			msg: types.InboxMessage{
				AuthorProfile: types.AuthorProfile{ActorType: "system", DisplayName: "system", TargetID: "system"},
			},
			want: []types.TrajectoryEntry{
				{Kind: consts.ParsedEventKindPromptInput, PromptKind: consts.PromptKindBaseInstructions, EventType: "thread_start", Runtime: "codex"},
				{Kind: consts.ParsedEventKindPromptInput, PromptKind: consts.PromptKindTurnInput, EventType: "fresh_start", Runtime: "codex"},
			},
		},
		{
			name:    "fresh wake start emits wake turn input",
			binding: baseBinding,
			msg: types.InboxMessage{
				MessageID:     "msg-1",
				Target:        "thread:alpha",
				AuthorProfile: types.AuthorProfile{ActorType: "human", DisplayName: "alice", TargetID: "alice"},
				Content:       "Please inspect the queue.",
			},
			want: []types.TrajectoryEntry{
				{Kind: consts.ParsedEventKindPromptInput, PromptKind: consts.PromptKindBaseInstructions, EventType: "thread_start", Runtime: "codex"},
				{Kind: consts.ParsedEventKindPromptInput, PromptKind: consts.PromptKindTurnInput, EventType: "wake", Runtime: "codex"},
			},
		},
		{
			name: "resumed wake keeps only the wake prompt input",
			binding: conversationBinding{
				channelID:       baseBinding.channelID,
				targetScopeType: baseBinding.targetScopeType,
				targetID:        baseBinding.targetID,
				serverSessionID: "thread-existing",
			},
			msg: types.InboxMessage{
				MessageID:     "msg-2",
				Target:        "thread:alpha",
				AuthorProfile: types.AuthorProfile{ActorType: "human", DisplayName: "bob", TargetID: "bob"},
				Content:       "Need a follow-up on the deploy.",
			},
			want: []types.TrajectoryEntry{
				{Kind: consts.ParsedEventKindPromptInput, PromptKind: consts.PromptKindTurnInput, EventType: "wake", Runtime: "codex"},
			},
		},
		{
			name: "resumed manual start emits resume prompt input",
			binding: conversationBinding{
				channelID:       baseBinding.channelID,
				targetScopeType: baseBinding.targetScopeType,
				targetID:        baseBinding.targetID,
				serverSessionID: "thread-existing",
			},
			msg: types.InboxMessage{
				AuthorProfile: types.AuthorProfile{ActorType: "system", DisplayName: "system", TargetID: "system"},
			},
			want: []types.TrajectoryEntry{
				{Kind: consts.ParsedEventKindPromptInput, PromptKind: consts.PromptKindResume, EventType: "resume", Runtime: "codex"},
			},
		},
	}

	for _, tt := range tests {
		tt := tt
		t.Run(tt.name, func(t *testing.T) {
			t.Parallel()

			prompts, err := compileSessionPrompts(
				t.TempDir(),
				baseAgent,
				runtimeconfig.TypeCodex,
				tt.binding,
				tt.msg,
				resolvedInstructionContext{skillDocParts: skillDocParts},
			)
			require.NoError(t, err)
			require.Len(t, prompts.PromptInputs, len(tt.want))
			for index, want := range tt.want {
				got := prompts.PromptInputs[index]
				require.Equal(t, want.Kind, got.Kind)
				require.Equal(t, want.PromptKind, got.PromptKind)
				require.Equal(t, want.EventType, got.EventType)
				require.Equal(t, want.Runtime, got.Runtime)
				if isSensitivePromptKind(got.PromptKind) {
					require.Empty(t, got.Text)
				} else {
					require.NotEmpty(t, got.Text)
				}
			}
		})
	}
}

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

	prompts, err := compileDeferredContinuationPrompts(
		t.TempDir(),
		agent.Config{
			ID:   "agent-1",
			Name: "reviewer",
		},
		runtimeconfig.TypeCodex,
		conversationBinding{
			channelID:       "channel-1",
			targetScopeType: "channel",
			targetID:        "thread:alpha",
		},
		types.InboxMessage{
			MessageID:     "msg-1",
			Target:        "thread:alpha",
			AuthorProfile: types.AuthorProfile{ActorType: "human", DisplayName: "alice", TargetID: "alice"},
			Content:       "Continue after the current turn.",
		},
		resolvedInstructionContext{},
		2,
	)
	require.NoError(t, err)
	require.Contains(t, prompts.Carrier.LaunchSurface("baseInstructions"), `You are "reviewer", an AI agent in AgentTeam.`)
	require.Empty(t, prompts.Carrier.LaunchSurface("contractCarrierFile"))
	require.Empty(t, prompts.Carrier.LaunchSurface("runtimeCarrier"))
	require.Len(t, prompts.PromptInputs, 2)
	require.Equal(t, "base_instructions", prompts.PromptInputs[0].PromptKind)
	require.Equal(t, "thread_start", prompts.PromptInputs[0].EventType)
	require.Equal(t, "deferred_continuation", prompts.PromptInputs[1].PromptKind)
	require.Equal(t, "deferred_continuation", prompts.PromptInputs[1].EventType)
	require.Empty(t, prompts.PromptInputs[0].Text)
	require.Contains(t, prompts.PromptInputs[1].Text, "Deferred follow-up after a busy turn:")
	require.Contains(t, prompts.PromptInputs[1].Text, "Continue after the current turn.")
}

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

	prompts, err := compileDeferredContinuationPrompts(
		t.TempDir(),
		agent.Config{
			ID:   "agent-1",
			Name: "reviewer",
		},
		runtimeconfig.TypeCodex,
		conversationBinding{
			channelID:       "channel-1",
			targetScopeType: "channel",
			targetID:        "#agentteam",
		},
		types.InboxMessage{
			MessageID:     "tsk-1",
			Target:        "#agentteam",
			AuthorProfile: types.AuthorProfile{ActorType: "human", DisplayName: "alice", TargetID: "alice"},
			Content:       "Task discussion update for #t9",
			MessageType:   "task_dispatch",
			Metadata: map[string]any{
				"task": map[string]any{
					"taskNumber": 9,
					"title":      "Fix reply routing",
					"channelRef": "#agentteam",
				},
				"taskDiscussion": map[string]any{
					"body": "Please keep the reply in the task discussion.",
					"createdBy": map[string]any{
						"name": "alice",
					},
				},
			},
		},
		resolvedInstructionContext{},
		2,
	)
	require.NoError(t, err)
	require.Contains(t, prompts.Carrier.LaunchSurface("freshPrompt"), "comment by @alice:\nPlease keep the reply in the task discussion.")
	require.Contains(t, prompts.Carrier.LaunchSurface("freshPrompt"), `reply: use mcp__agentteam__message_send with the exact task scope target from the current message header`)
	require.NotContains(t, prompts.Carrier.LaunchSurface("freshPrompt"), "routing_kind")
	require.Contains(t, prompts.Carrier.LaunchSurface("freshPrompt"), "use mcp__agentteam__message_send with the task scope target for task discussion replies, or for milestone/channel-thread updates")
}

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

	prompts, err := compileDeferredContinuationPrompts(
		t.TempDir(),
		agent.Config{
			ID:   "agent-1",
			Name: "reviewer",
		},
		runtimeconfig.TypeCodex,
		conversationBinding{
			channelID:       "channel-1",
			targetScopeType: "channel",
			targetID:        "thread:alpha",
			serverSessionID: "thread-existing",
		},
		types.InboxMessage{
			MessageID:     "msg-1",
			Target:        "thread:alpha",
			AuthorProfile: types.AuthorProfile{ActorType: "human", DisplayName: "alice", TargetID: "alice"},
			Content:       "Continue after the current turn.",
		},
		resolvedInstructionContext{},
		2,
	)
	require.NoError(t, err)
	require.Len(t, prompts.PromptInputs, 1)
	require.Equal(t, "deferred_continuation", prompts.PromptInputs[0].PromptKind)
	require.Equal(t, "deferred_continuation", prompts.PromptInputs[0].EventType)
	require.Contains(t, prompts.PromptInputs[0].Text, "Deferred follow-up after a busy turn:")
	require.Contains(t, prompts.PromptInputs[0].Text, "Continue after the current turn.")
}

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

	prompts, err := compileSessionPrompts(
		t.TempDir(),
		agent.Config{
			ID:          "agent-1",
			Name:        "reviewer",
			Description: "Review the queue and respond precisely.",
		},
		runtimeconfig.TypeClaudeCode,
		conversationBinding{
			channelID:       "channel-1",
			targetScopeType: "channel",
			targetID:        "thread:alpha",
			serverSessionID: "thread-existing",
		},
		types.InboxMessage{
			MessageID:     "msg-1",
			Target:        "thread:alpha",
			AuthorProfile: types.AuthorProfile{ActorType: "human", DisplayName: "alice", TargetID: "alice"},
			Content:       "Please continue the rollout.",
		},
		testResolvedInstructions(),
	)
	require.NoError(t, err)

	require.Empty(t, prompts.Carrier.LaunchSurface("prompt"))
	require.Contains(t, prompts.Carrier.LaunchSurface("baseInstructions"), `You are "reviewer", an AI agent in AgentTeam.`)
	require.Contains(t, prompts.Carrier.LaunchSurface("baseInstructions"), "## Initial role")
	require.Empty(t, prompts.Carrier.LaunchSurface("developerInstructions"))
	require.Empty(t, prompts.Carrier.LaunchSurface("contractCarrierFile"))
	require.Empty(t, prompts.Carrier.LaunchSurface("runtimeCarrier"))
	require.Empty(t, prompts.Carrier.LaunchSurface("freshPrompt"))

	require.NotContains(t, prompts.Carrier.LaunchSurface("resumePrompt"), "## Channel Reference")
	require.NotContains(t, prompts.Carrier.LaunchSurface("resumePrompt"), "## App: GitHub")
	require.Contains(t, prompts.Carrier.LaunchSurface("resumePrompt"), "Please continue the rollout.")
	require.Len(t, prompts.PromptInputs, 1)
	require.Equal(t, "turn_input", prompts.PromptInputs[0].PromptKind)
	require.Equal(t, "wake", prompts.PromptInputs[0].EventType)
	require.Equal(t, "claude", prompts.PromptInputs[0].Runtime)
}

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

	prompts, err := compileDeferredContinuationPrompts(
		t.TempDir(),
		agent.Config{
			ID:          "agent-1",
			Name:        "reviewer",
			Description: "Review the queue and respond precisely.",
		},
		runtimeconfig.TypeClaudeCode,
		conversationBinding{
			channelID:       "channel-1",
			targetScopeType: "channel",
			targetID:        "thread:alpha",
			serverSessionID: "thread-existing",
		},
		types.InboxMessage{
			MessageID:     "msg-1",
			Target:        "thread:alpha",
			AuthorProfile: types.AuthorProfile{ActorType: "human", DisplayName: "alice", TargetID: "alice"},
			Content:       "Continue after the current turn.",
		},
		testResolvedInstructions(),
		2,
	)
	require.NoError(t, err)

	require.Empty(t, prompts.Carrier.LaunchSurface("prompt"))
	require.Contains(t, prompts.Carrier.LaunchSurface("baseInstructions"), `You are "reviewer", an AI agent in AgentTeam.`)
	require.Contains(t, prompts.Carrier.LaunchSurface("baseInstructions"), "## Initial role")
	require.Empty(t, prompts.Carrier.LaunchSurface("developerInstructions"))
	require.Empty(t, prompts.Carrier.LaunchSurface("contractCarrierFile"))
	require.Empty(t, prompts.Carrier.LaunchSurface("runtimeCarrier"))
	require.Empty(t, prompts.Carrier.LaunchSurface("freshPrompt"))
	require.NotContains(t, prompts.Carrier.LaunchSurface("resumePrompt"), "## Channel Reference")
	require.NotContains(t, prompts.Carrier.LaunchSurface("resumePrompt"), "## App: GitHub")
	require.Contains(t, prompts.Carrier.LaunchSurface("resumePrompt"), "Deferred follow-up after a busy turn:")

	require.Len(t, prompts.PromptInputs, 1)
	require.Equal(t, "deferred_continuation", prompts.PromptInputs[0].PromptKind)
	require.Equal(t, "deferred_continuation", prompts.PromptInputs[0].EventType)
	require.Equal(t, "claude", prompts.PromptInputs[0].Runtime)
	require.Contains(t, prompts.PromptInputs[0].Text, "Deferred follow-up after a busy turn:")
	require.Contains(t, prompts.PromptInputs[0].Text, "Continue after the current turn.")
}

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

	prompts, err := compileDeferredContinuationPrompts(
		t.TempDir(),
		agent.Config{
			ID:   "agent-1",
			Name: "reviewer",
		},
		runtimeconfig.TypeCodex,
		conversationBinding{
			channelID:       "channel-1",
			targetScopeType: "channel",
			targetID:        "#agentteam",
		},
		types.InboxMessage{
			MessageID:     "msg-task-1",
			Target:        "#agentteam",
			AuthorProfile: types.AuthorProfile{ActorType: "human", DisplayName: "alice", TargetID: "alice"},
			Content:       "Task discussion update for #t9",
			MessageType:   "task_dispatch",
			Metadata: map[string]any{
				"task": map[string]any{
					"taskNumber": 9,
					"title":      "Fix reply routing",
					"channelRef": "#agentteam",
				},
				"taskDiscussion": map[string]any{
					"body": "Please keep the reply in the task discussion.",
					"createdBy": map[string]any{
						"name": "alice",
					},
				},
			},
		},
		resolvedInstructionContext{},
		1,
	)
	require.NoError(t, err)
	require.Len(t, prompts.PromptInputs, 2)
	require.Equal(t, "deferred_continuation", prompts.PromptInputs[1].PromptKind)
	require.Contains(t, prompts.PromptInputs[1].Text, `task discussion: #t9 "Fix reply routing"`)
	require.Contains(t, prompts.PromptInputs[1].Text, "comment by @alice:\nPlease keep the reply in the task discussion.")
	require.Contains(t, prompts.PromptInputs[1].Text, `reply: use mcp__agentteam__message_send with the exact task scope target from the current message header`)
	require.NotContains(t, prompts.PromptInputs[1].Text, "routing_kind")
}

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

	prompts, err := compileSessionPrompts(
		t.TempDir(),
		agent.Config{
			ID:          "agent-1",
			Name:        "reviewer",
			Description: "Review the queue and respond precisely.",
		},
		runtimeconfig.TypeOpenCode,
		conversationBinding{
			channelID:       "channel-1",
			targetScopeType: "channel",
			targetID:        "thread:alpha",
			serverSessionID: "thread-existing",
		},
		types.InboxMessage{
			MessageID:     "msg-1",
			Target:        "thread:alpha",
			AuthorProfile: types.AuthorProfile{ActorType: "human", DisplayName: "alice", TargetID: "alice"},
			Content:       "Please continue the rollout.",
		},
		testResolvedInstructions(),
	)
	require.NoError(t, err)

	require.Equal(t, "AGENTS.md", prompts.Carrier.LaunchSurface("contractCarrierFile"))
	require.Contains(t, prompts.Carrier.LaunchSurface("runtimeCarrier"), `You are "reviewer", an AI agent in AgentTeam.`)
	require.Contains(t, prompts.Carrier.LaunchSurface("runtimeCarrier"), "## Initial role")
	require.Empty(t, prompts.Carrier.LaunchSurface("baseInstructions"))
	require.Empty(t, prompts.Carrier.LaunchSurface("developerInstructions"))
	require.Empty(t, prompts.Carrier.LaunchSurface("freshPrompt"))
	require.Empty(t, prompts.Carrier.LaunchSurface("resumePrompt"))
	require.NotContains(t, prompts.Carrier.LaunchSurface("prompt"), "## Channel Reference")
	require.NotContains(t, prompts.Carrier.LaunchSurface("prompt"), "## App: GitHub")
	require.Contains(t, prompts.Carrier.LaunchSurface("prompt"), "Please continue the rollout.")

	require.Len(t, prompts.PromptInputs, 1)
	require.Equal(t, "turn_input", prompts.PromptInputs[0].PromptKind)
	require.Equal(t, "wake", prompts.PromptInputs[0].EventType)
	require.Equal(t, "opencode", prompts.PromptInputs[0].Runtime)
	require.NotEmpty(t, prompts.PromptInputs[0].Text)
	require.Len(t, prompts.CompileMetrics, 3)
	require.Equal(t, "thread_contract", prompts.CompileMetrics[0].stage)
	require.Equal(t, metrics.PromptSessionFreshnessResume, prompts.CompileMetrics[1].freshness)
	require.Equal(t, metrics.PromptSessionFreshnessFresh, prompts.CompileMetrics[2].freshness)
	require.Equal(t, prompts.CompileMetrics[1].rendered, prompts.CompileMetrics[2].rendered)
}

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

	prompts, err := compileSessionPrompts(
		t.TempDir(),
		agent.Config{ID: "agent-1", Name: "reviewer", Description: "Review the queue."},
		runtimeconfig.TypeKimi,
		conversationBinding{channelID: "channel-1", targetScopeType: "channel", targetID: "thread:alpha"},
		types.InboxMessage{MessageID: "msg-1", Target: "thread:alpha", AuthorProfile: types.AuthorProfile{ActorType: "human", DisplayName: "alice", TargetID: "alice"}, Content: "Please continue."},
		testResolvedInstructions(),
	)
	require.NoError(t, err)
	require.Contains(t, prompts.Carrier.LaunchSurface("baseInstructions"), `You are "reviewer", an AI agent in AgentTeam.`)
	require.Contains(t, prompts.Carrier.LaunchSurface("baseInstructions"), "## Initial role")
	require.Contains(t, prompts.Carrier.LaunchSurface("baseInstructions"), "mcp__agentteam__message_send")
	require.NotContains(t, prompts.Carrier.LaunchSurface("baseInstructions"), "mcp_agentteam_message_send")
	require.Contains(t, prompts.Carrier.LaunchSurface("freshPrompt"), "Please continue.")
	require.Empty(t, prompts.Carrier.LaunchSurface("prompt"))
	require.Len(t, prompts.PromptInputs, 2)
	require.Equal(t, consts.PromptKindBaseInstructions, prompts.PromptInputs[0].PromptKind)
	require.Equal(t, consts.PromptKindTurnInput, prompts.PromptInputs[1].PromptKind)
}

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

	prompts, err := compileSessionPrompts(
		t.TempDir(),
		agent.Config{ID: "agent-1", Name: "reviewer", Description: "Review the queue."},
		runtimeconfig.TypeKimi,
		conversationBinding{channelID: "channel-1", targetScopeType: "channel", targetID: "thread:alpha", serverSessionID: "kimi-session"},
		types.InboxMessage{MessageID: "msg-1", Target: "thread:alpha", AuthorProfile: types.AuthorProfile{ActorType: "human", DisplayName: "alice", TargetID: "alice"}, Content: "Please resume."},
		testResolvedInstructions(),
	)
	require.NoError(t, err)
	require.Contains(t, prompts.Carrier.LaunchSurface("baseInstructions"), `You are "reviewer", an AI agent in AgentTeam.`)
	require.Contains(t, prompts.Carrier.LaunchSurface("freshPrompt"), "## Channel Reference")
	require.Contains(t, prompts.Carrier.LaunchSurface("resumePrompt"), "Please resume.")
	require.NotContains(t, prompts.Carrier.LaunchSurface("resumePrompt"), "## Channel Reference")
	require.Len(t, prompts.PromptInputs, 1)
	require.Equal(t, consts.PromptKindTurnInput, prompts.PromptInputs[0].PromptKind)
}

func TestCompiledPromptsTrackSelectedMemoryRoot(t *testing.T) {
	compile := func(t *testing.T, workDir string) compiledSessionPrompts {
		t.Helper()
		prompts, err := compileSessionPrompts(
			workDir,
			agent.Config{ID: "agent-1", Name: "reviewer"},
			runtimeconfig.TypeCodex,
			conversationBinding{channelID: "channel-1", targetScopeType: "channel", targetID: "#agentteam"},
			types.InboxMessage{MessageID: "msg-1", Target: "#agentteam", Content: "Continue."},
			testResolvedInstructions(),
		)
		require.NoError(t, err)
		return prompts
	}

	workDir := t.TempDir()
	require.True(t, compiledPromptsUseWorkspaceRootMemory(compile(t, workDir)))

	require.NoError(t, os.MkdirAll(filepath.Join(workDir, "memory"), 0o755))
	require.NoError(t, os.WriteFile(filepath.Join(workDir, "memory", "MEMORY.md"), []byte("# Memory\n"), 0o644))
	require.False(t, compiledPromptsUseWorkspaceRootMemory(compile(t, workDir)))
}
