package kb

import (
	"context"
	"encoding/json"
	"errors"
	"testing"

	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/AgentTeam/internal/service/resource/repos"
	"github.com/tidbcloud/AgentTeam/internal/store/content"
	"github.com/tidbcloud/AgentTeam/internal/store/kb"
	reposstore "github.com/tidbcloud/AgentTeam/internal/store/resource/repos"
)

func TestNativeKBSourceSkipsRepositoryAccessAndDeletionAGSCalls(t *testing.T) {
	ctx := t.Context()
	svc := newKBServiceForTest(t)
	wikiStore := svc.wikiStore.(*fakeAGSRepositoryStore)
	base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
	require.NoError(t, err)
	source, err := svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
	require.NoError(t, err)
	readProfile := kb.KnowledgeBaseRepositoryAccessProfileRead
	grant, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{
		SubjectType: "user", SubjectID: "viewer", Role: "view", RepositoryAccessProfile: &readProfile,
	})
	require.NoError(t, err)
	wikiStore.grants = nil
	wikiStore.revokes = nil
	wikiStore.deletes = nil
	svc.contentAuthority = &mutableKBSourceAuthorityReader{states: map[string]string{
		source.ID: content.AuthorityStateNativeActive,
	}}

	manageProfile := kb.KnowledgeBaseRepositoryAccessProfileManage
	_, err = svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{
		GrantID: grant.ID, RepositoryAccessProfile: &manageProfile,
	})
	require.NoError(t, err)
	require.Empty(t, wikiStore.grants)
	require.Empty(t, wikiStore.revokes)
	rows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, grant.ID)
	require.NoError(t, err)
	require.Len(t, rows, 2)
	for _, row := range rows {
		require.True(t, row.Materialized, "native product access projection must remain live without AGS")
		require.Equal(t, reposstore.AccessStatusCurrent, row.Status)
		require.Equal(t, reposstore.AccessPermissionAdmin, row.Permission)
	}
	newGrant, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{
		SubjectType: "user", SubjectID: "new-viewer", Role: "view", RepositoryAccessProfile: &readProfile,
	})
	require.NoError(t, err)
	require.Empty(t, wikiStore.grants)
	newRows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, newGrant.ID)
	require.NoError(t, err)
	require.Len(t, newRows, 2)
	for _, row := range newRows {
		require.True(t, row.Materialized)
		require.Equal(t, reposstore.AccessStatusCurrent, row.Status)
	}
	require.NoError(t, svc.DeleteKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, newGrant.ID))
	require.Empty(t, wikiStore.revokes)
	newRows, err = svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, newGrant.ID)
	require.NoError(t, err)
	for _, row := range newRows {
		require.False(t, row.Materialized)
		require.Equal(t, reposstore.AccessStatusRevoked, row.Status)
	}

	err = svc.DeleteSource(ctx, "wsp_1", "owner", base.ID, source.ID)
	require.ErrorContains(t, err, "Legacy KB source operations are unavailable after native activation")
	require.Empty(t, wikiStore.deletes)
}

func TestKBServiceDowngradesMaterializedRepositoryAccessToRemainingIntent(t *testing.T) {
	ctx := context.Background()
	svc := newKBServiceForTest(t)
	wikiStore := svc.wikiStore.(*fakeAGSRepositoryStore)
	base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
	require.NoError(t, err)
	_, err = svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
	require.NoError(t, err)
	writeProfile := kb.KnowledgeBaseRepositoryAccessProfileWrite
	grant, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{SubjectType: "user", SubjectID: "viewer", Role: "edit", RepositoryAccessProfile: &writeProfile})
	require.NoError(t, err)
	rows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, grant.ID)
	require.NoError(t, err)
	require.Len(t, rows, 2)
	upsertSiblingRepositoryAccessIntent(t, ctx, svc, rows, "kbg_read_intent", reposstore.AccessPermissionRead, true)
	wikiStore.grants = nil
	wikiStore.revokes = nil
	noneProfile := kb.KnowledgeBaseRepositoryAccessProfileNone

	updated, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{GrantID: grant.ID, RepositoryAccessProfile: &noneProfile})
	require.NoError(t, err)
	require.Equal(t, kbRepositoryAccessStatusNotGranted, updated.RepositoryAccessStatus)
	require.Empty(t, wikiStore.revokes)
	require.Len(t, wikiStore.grants, 2)
	for _, grant := range wikiStore.grants {
		require.Equal(t, reposstore.AccessPermissionRead, grant.Permission)
		require.True(t, grant.AllowExistingDirectUpdate)
	}

	rows, err = svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, grant.ID)
	require.NoError(t, err)
	require.Len(t, rows, 2)
	for _, row := range rows {
		require.Equal(t, reposstore.AccessStatusRevoked, row.Status)
	}
}

func TestKBServiceKeepsStrongerMaterializedRepositoryAccessForSiblingIntent(t *testing.T) {
	ctx := context.Background()
	svc := newKBServiceForTest(t)
	wikiStore := svc.wikiStore.(*fakeAGSRepositoryStore)
	base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
	require.NoError(t, err)
	source, err := svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
	require.NoError(t, err)
	repos, err := svc.repositoryStore.ListForResource(ctx, "wsp_1", reposstore.ResourceTypeKBSource, source.ID)
	require.NoError(t, err)
	upsertRepositoryAccessIntent(t, ctx, svc, repos, "viewer", "kbg_write_intent", reposstore.AccessPermissionWrite, kb.KnowledgeBaseRepositoryAccessProfileWrite, true)
	wikiStore.grants = nil
	readProfile := kb.KnowledgeBaseRepositoryAccessProfileRead

	grant, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{SubjectType: "user", SubjectID: "viewer", Role: "view", RepositoryAccessProfile: &readProfile})
	require.NoError(t, err)
	require.Equal(t, kbRepositoryAccessStatusCurrent, grant.RepositoryAccessStatus)
	require.Len(t, wikiStore.grants, 2)
	for _, request := range wikiStore.grants {
		require.Equal(t, reposstore.AccessPermissionWrite, request.Permission)
		require.True(t, request.AllowExistingDirectUpdate)
	}

	rows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, grant.ID)
	require.NoError(t, err)
	require.Len(t, rows, 2)
	for _, row := range rows {
		require.Equal(t, reposstore.AccessPermissionRead, row.Permission)
		require.True(t, row.Materialized)
		require.Equal(t, reposstore.AccessStatusCurrent, row.Status)
	}
}

func TestKBServiceHumanRepositoryAccessIncludesInsightsRepo(t *testing.T) {
	ctx := context.Background()
	svc := newKBServiceForTest(t)
	base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
	require.NoError(t, err)
	_, err = svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
	require.NoError(t, err)
	readProfile := kb.KnowledgeBaseRepositoryAccessProfileRead

	grant, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{SubjectType: "user", SubjectID: "viewer", Role: "view", RepositoryAccessProfile: &readProfile})
	require.NoError(t, err)

	rows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, grant.ID)
	require.NoError(t, err)
	require.Len(t, rows, 2)
	byRole := make(map[string]reposstore.ResourceRepositoryAccessGrant, len(rows))
	for _, row := range rows {
		byRole[row.RepoRole] = row
		require.Equal(t, reposstore.AccessPermissionRead, row.Permission)
		require.True(t, row.Materialized)
		require.Equal(t, reposstore.AccessStatusCurrent, row.Status)
	}
	require.Contains(t, byRole, reposstore.RepoRolePrimary)
	require.Contains(t, byRole, reposstore.RepoRoleInsights)
}

func TestKBServiceSourceRepositoryOverrideManageMaterializesAdmin(t *testing.T) {
	ctx := context.Background()
	svc := newKBServiceForTest(t)
	wikiStore := svc.wikiStore.(*fakeAGSRepositoryStore)
	base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
	require.NoError(t, err)
	source, err := svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
	require.NoError(t, err)
	wikiStore.grants = nil
	readProfile := kb.KnowledgeBaseRepositoryAccessProfileRead
	manageProfile := kb.KnowledgeBaseRepositoryAccessProfileManage

	grant, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{
		SubjectType:             "user",
		SubjectID:               "viewer",
		Role:                    "view",
		RepositoryAccessProfile: &readProfile,
		RepositoryOverrides:     []KBPermissionRepositoryOverrideMutation{{SourceID: source.ID, RepoRole: reposstore.RepoRolePrimary, RepositoryAccessProfile: &manageProfile}},
	})
	require.NoError(t, err)
	require.Equal(t, kb.KnowledgeBaseRepositoryAccessProfileRead, grant.RepositoryAccessProfile)
	require.Equal(t, kbRepositoryAccessStatusCurrent, grant.RepositoryAccessStatus)
	require.Len(t, grant.SourceRepositoryAccess, 2)
	var sourceAccess KBPermissionRepositoryAccess
	for _, row := range grant.SourceRepositoryAccess {
		if row.RepoRole == reposstore.RepoRolePrimary {
			sourceAccess = row
			break
		}
	}
	require.Equal(t, source.ID, sourceAccess.SourceID)
	require.Equal(t, reposstore.RepoRolePrimary, sourceAccess.RepoRole)
	require.Equal(t, kb.KnowledgeBaseRepositoryAccessProfileRead, sourceAccess.InheritedRepositoryAccessProfile)
	require.Equal(t, kb.KnowledgeBaseRepositoryAccessProfileManage, sourceAccess.OverrideRepositoryAccessProfile)
	require.Equal(t, kb.KnowledgeBaseRepositoryAccessProfileManage, sourceAccess.EffectiveRepositoryAccessProfile)
	require.Equal(t, kbRepositoryAccessStatusCurrent, sourceAccess.RepositoryAccessStatus)

	rows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, grant.ID)
	require.NoError(t, err)
	require.Len(t, rows, 2)
	rowByRole := make(map[string]reposstore.ResourceRepositoryAccessGrant, len(rows))
	for _, row := range rows {
		rowByRole[row.RepoRole] = row
		require.Equal(t, reposstore.AccessStatusCurrent, row.Status)
		require.True(t, row.Materialized)
	}
	require.Equal(t, reposstore.AccessPermissionAdmin, rowByRole[reposstore.RepoRolePrimary].Permission)
	require.Equal(t, kb.KnowledgeBaseRepositoryAccessProfileManage, rowByRole[reposstore.RepoRolePrimary].IntentProfile)
	require.Equal(t, reposstore.AccessPermissionRead, rowByRole[reposstore.RepoRoleInsights].Permission)
	require.Equal(t, kb.KnowledgeBaseRepositoryAccessProfileRead, rowByRole[reposstore.RepoRoleInsights].IntentProfile)
	require.Len(t, wikiStore.grants, 2)
	grantByRepo := make(map[string]repos.ResourceRepositoryCollaboratorGrant, len(wikiStore.grants))
	for _, request := range wikiStore.grants {
		grantByRepo[request.Repository.FullName] = request
		require.Equal(t, "viewer", request.Actor.Subject)
	}
	require.Equal(t, reposstore.AccessPermissionAdmin, grantByRepo["owner/tidb"].Permission)
	require.Equal(t, reposstore.AccessPermissionRead, grantByRepo["owner/tidb.kb"].Permission)
}

func TestKBServiceCreateSourcePreservesCreatorManageRepositoryAccess(t *testing.T) {
	ctx := context.Background()
	svc := newKBServiceForTest(t)
	wikiStore := svc.wikiStore.(*fakeAGSRepositoryStore)
	base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
	require.NoError(t, err)
	permissions, err := svc.ListKnowledgeBasePermissions(ctx, "wsp_1", "owner", base.ID)
	require.NoError(t, err)
	require.NotNil(t, permissions.Owner)
	manageProfile := kb.KnowledgeBaseRepositoryAccessProfileManage
	ownerGrant, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{GrantID: permissions.Owner.ID, RepositoryAccessProfile: &manageProfile})
	require.NoError(t, err)
	require.Equal(t, kb.KnowledgeBaseRepositoryAccessProfileManage, ownerGrant.RepositoryAccessProfile)
	wikiStore.grants = nil

	_, err = svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
	require.NoError(t, err)
	permissions, err = svc.ListKnowledgeBasePermissions(ctx, "wsp_1", "owner", base.ID)
	require.NoError(t, err)
	require.NotNil(t, permissions.Owner)
	require.Equal(t, kb.KnowledgeBaseRepositoryAccessProfileManage, permissions.Owner.RepositoryAccessProfile)
	require.Len(t, wikiStore.grants, 2)
	grantByRepo := make(map[string]repos.ResourceRepositoryCollaboratorGrant, len(wikiStore.grants))
	for _, request := range wikiStore.grants {
		grantByRepo[request.Repository.FullName] = request
	}
	require.Equal(t, reposstore.AccessPermissionAdmin, grantByRepo["owner/tidb"].Permission)
	require.Equal(t, reposstore.AccessPermissionAdmin, grantByRepo["owner/tidb.kb"].Permission)
}

func TestKBServiceCreateSourceBackfillsCreatorRepositoryAccessForExistingSources(t *testing.T) {
	ctx := context.Background()
	svc := newKBServiceForTest(t)
	wikiStore := svc.wikiStore.(*fakeAGSRepositoryStore)
	base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
	require.NoError(t, err)
	legacySource, err := svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
	require.NoError(t, err)
	ownerGrant, err := svc.store.GetKnowledgeBaseGrant(ctx, "wsp_1", base.ID, "user", "owner")
	require.NoError(t, err)
	accessRows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, ownerGrant.ID)
	require.NoError(t, err)
	require.Len(t, accessRows, 2)
	for _, row := range accessRows {
		row.Status = reposstore.AccessStatusRevoked
		row.Materialized = false
		row.RevokedBy = "legacy-test"
		_, err := svc.repositoryStore.UpsertAccessGrant(ctx, row)
		require.NoError(t, err)
	}
	ownerGrant.RepositoryAccessProfile = kb.KnowledgeBaseRepositoryAccessProfileNone
	_, err = svc.store.UpsertKnowledgeBaseGrant(ctx, ownerGrant)
	require.NoError(t, err)
	wikiStore.grants = nil

	_, err = svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "PD", IndexStatus: "ready"})
	require.NoError(t, err)

	permissions, err := svc.ListKnowledgeBasePermissions(ctx, "wsp_1", "owner", base.ID)
	require.NoError(t, err)
	require.NotNil(t, permissions.Owner)
	require.Equal(t, kb.KnowledgeBaseRepositoryAccessProfileWrite, permissions.Owner.RepositoryAccessProfile)
	require.Len(t, permissions.Owner.SourceRepositoryAccess, 4)
	legacyRows := 0
	for _, row := range permissions.Owner.SourceRepositoryAccess {
		require.Equalf(t, kbRepositoryAccessStatusCurrent, row.RepositoryAccessStatus, "source=%s role=%s", row.SourceName, row.RepoRole)
		if row.SourceID == legacySource.ID {
			legacyRows++
		}
	}
	require.Equal(t, 2, legacyRows)
	require.Len(t, wikiStore.grants, 4)
	grantByRepo := make(map[string]repos.ResourceRepositoryCollaboratorGrant, len(wikiStore.grants))
	for _, request := range wikiStore.grants {
		grantByRepo[request.Repository.FullName] = request
	}
	require.Equal(t, reposstore.AccessPermissionWrite, grantByRepo["owner/tidb"].Permission)
	require.Equal(t, reposstore.AccessPermissionWrite, grantByRepo["owner/tidb.kb"].Permission)
	require.Equal(t, reposstore.AccessPermissionWrite, grantByRepo["owner/pd"].Permission)
	require.Equal(t, reposstore.AccessPermissionWrite, grantByRepo["owner/pd.kb"].Permission)
}

func TestKBServiceCreateSourceBackfillsCreatorRepositoryAccessWhenProfileAlreadyGranted(t *testing.T) {
	ctx := context.Background()
	svc := newKBServiceForTest(t)
	wikiStore := svc.wikiStore.(*fakeAGSRepositoryStore)
	base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
	require.NoError(t, err)
	legacySource, err := svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
	require.NoError(t, err)
	ownerGrant, err := svc.store.GetKnowledgeBaseGrant(ctx, "wsp_1", base.ID, "user", "owner")
	require.NoError(t, err)
	require.Equal(t, kb.KnowledgeBaseRepositoryAccessProfileWrite, ownerGrant.RepositoryAccessProfile)
	accessRows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, ownerGrant.ID)
	require.NoError(t, err)
	require.Len(t, accessRows, 2)
	for _, row := range accessRows {
		row.Status = reposstore.AccessStatusRevoked
		row.Materialized = false
		row.RevokedBy = "legacy-test"
		_, err := svc.repositoryStore.UpsertAccessGrant(ctx, row)
		require.NoError(t, err)
	}
	wikiStore.grants = nil

	created, err := svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{
		SourceType: "codebase",
		RepoMode:   "mirror",
		Name:       "PD",
		Mirror: KBSourceMirrorMutation{
			RemoteURL:    "https://example.com/pingcap/pd.git",
			UpstreamType: kb.SourceMirrorUpstreamTypeGenericGit,
			DefaultRef:   "main",
		},
	})
	require.NoError(t, err)
	_, err = svc.RequestSourceMirrorSync(ctx, "wsp_1", "owner", base.ID, created.ID, "main")
	require.NoError(t, err)

	permissions, err := svc.ListKnowledgeBasePermissions(ctx, "wsp_1", "owner", base.ID)
	require.NoError(t, err)
	require.NotNil(t, permissions.Owner)
	require.Equal(t, kb.KnowledgeBaseRepositoryAccessProfileWrite, permissions.Owner.RepositoryAccessProfile)
	require.Len(t, permissions.Owner.SourceRepositoryAccess, 4)
	legacyRows := 0
	for _, row := range permissions.Owner.SourceRepositoryAccess {
		require.Equalf(t, kbRepositoryAccessStatusCurrent, row.RepositoryAccessStatus, "source=%s role=%s", row.SourceName, row.RepoRole)
		if row.SourceID == legacySource.ID {
			legacyRows++
		}
	}
	require.Equal(t, 2, legacyRows)
	require.Len(t, wikiStore.grants, 4)
}

func TestKBServiceSourceRepositoryOverrideNoneAndClear(t *testing.T) {
	ctx := context.Background()
	svc := newKBServiceForTest(t)
	wikiStore := svc.wikiStore.(*fakeAGSRepositoryStore)
	base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
	require.NoError(t, err)
	source, err := svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
	require.NoError(t, err)
	writeProfile := kb.KnowledgeBaseRepositoryAccessProfileWrite
	grant, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{SubjectType: "user", SubjectID: "viewer", Role: "edit", RepositoryAccessProfile: &writeProfile})
	require.NoError(t, err)
	wikiStore.grants = nil
	wikiStore.revokes = nil
	noneProfile := kb.KnowledgeBaseRepositoryAccessProfileNone

	updated, err := svc.UpdateKnowledgeBasePermissionRepositoryOverrides(ctx, "wsp_1", "owner", base.ID, grant.ID, []KBPermissionRepositoryOverrideMutation{{SourceID: source.ID, RepoRole: reposstore.RepoRolePrimary, RepositoryAccessProfile: &noneProfile}})
	require.NoError(t, err)
	require.Equal(t, kb.KnowledgeBaseRepositoryAccessProfileWrite, updated.RepositoryAccessProfile)
	require.Equal(t, kbRepositoryAccessStatusCurrent, updated.RepositoryAccessStatus)
	require.Len(t, updated.SourceRepositoryAccess, 2)
	canonicalAccess := sourceRepositoryAccessForRole(t, updated.SourceRepositoryAccess, reposstore.RepoRolePrimary)
	require.Equal(t, kb.KnowledgeBaseRepositoryAccessProfileNone, canonicalAccess.OverrideRepositoryAccessProfile)
	require.Equal(t, kb.KnowledgeBaseRepositoryAccessProfileNone, canonicalAccess.EffectiveRepositoryAccessProfile)
	require.Equal(t, kbRepositoryAccessStatusNotGranted, canonicalAccess.RepositoryAccessStatus)
	require.Len(t, wikiStore.revokes, 1)
	require.Equal(t, "owner/tidb", wikiStore.revokes[0].Repository.FullName)

	rows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, grant.ID)
	require.NoError(t, err)
	require.Len(t, rows, 2)
	rowsByRole := make(map[string]reposstore.ResourceRepositoryAccessGrant, len(rows))
	for _, row := range rows {
		rowsByRole[row.RepoRole] = row
	}
	require.Equal(t, reposstore.AccessStatusRevoked, rowsByRole[reposstore.RepoRolePrimary].Status)
	require.Equal(t, reposstore.AccessStatusCurrent, rowsByRole[reposstore.RepoRoleInsights].Status)

	wikiStore.grants = nil
	wikiStore.revokes = nil
	restored, err := svc.UpdateKnowledgeBasePermissionRepositoryOverrides(ctx, "wsp_1", "owner", base.ID, grant.ID, []KBPermissionRepositoryOverrideMutation{{SourceID: source.ID, RepoRole: reposstore.RepoRolePrimary}})
	require.NoError(t, err)
	require.Equal(t, kbRepositoryAccessStatusCurrent, restored.RepositoryAccessStatus)
	require.Len(t, restored.SourceRepositoryAccess, 2)
	canonicalAccess = sourceRepositoryAccessForRole(t, restored.SourceRepositoryAccess, reposstore.RepoRolePrimary)
	require.Empty(t, canonicalAccess.OverrideRepositoryAccessProfile)
	require.Equal(t, kb.KnowledgeBaseRepositoryAccessProfileWrite, canonicalAccess.EffectiveRepositoryAccessProfile)
	require.Equal(t, kbRepositoryAccessStatusCurrent, canonicalAccess.RepositoryAccessStatus)
	require.Empty(t, wikiStore.revokes)
	require.Len(t, wikiStore.grants, 2)
	grantByRepo := make(map[string]repos.ResourceRepositoryCollaboratorGrant, len(wikiStore.grants))
	for _, request := range wikiStore.grants {
		grantByRepo[request.Repository.FullName] = request
		require.Equal(t, reposstore.AccessPermissionWrite, request.Permission)
	}
	require.False(t, grantByRepo["owner/tidb"].AllowExistingDirectUpdate)
	require.True(t, grantByRepo["owner/tidb.kb"].AllowExistingDirectUpdate)
}

func TestKBServiceAuditsSourceRepositoryOverrideIntent(t *testing.T) {
	ctx := context.Background()
	svc := newKBServiceForTest(t)
	base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
	require.NoError(t, err)
	source, err := svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
	require.NoError(t, err)
	writeProfile := kb.KnowledgeBaseRepositoryAccessProfileWrite
	grant, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{SubjectType: "user", SubjectID: "viewer", Role: "edit", RepositoryAccessProfile: &writeProfile})
	require.NoError(t, err)
	manageProfile := kb.KnowledgeBaseRepositoryAccessProfileManage
	readProfile := kb.KnowledgeBaseRepositoryAccessProfileRead

	_, err = svc.UpdateKnowledgeBasePermissionRepositoryOverrides(ctx, "wsp_1", "owner", base.ID, grant.ID, []KBPermissionRepositoryOverrideMutation{{SourceID: source.ID, RepoRole: reposstore.RepoRolePrimary, RepositoryAccessProfile: &manageProfile}})
	require.NoError(t, err)
	_, err = svc.UpdateKnowledgeBasePermissionRepositoryOverrides(ctx, "wsp_1", "owner", base.ID, grant.ID, []KBPermissionRepositoryOverrideMutation{{SourceID: source.ID, RepoRole: reposstore.RepoRolePrimary, RepositoryAccessProfile: &readProfile}})
	require.NoError(t, err)
	_, err = svc.UpdateKnowledgeBasePermissionRepositoryOverrides(ctx, "wsp_1", "owner", base.ID, grant.ID, []KBPermissionRepositoryOverrideMutation{{SourceID: source.ID, RepoRole: reposstore.RepoRolePrimary}})
	require.NoError(t, err)

	events, err := svc.ListAuditEvents(ctx, "wsp_1", "owner", base.ID, 1, 100)
	require.NoError(t, err)
	found := map[string]bool{}
	for _, event := range events {
		if event.ResourceType != "source_repository_access_override" {
			continue
		}
		var details map[string]any
		require.NoError(t, json.Unmarshal([]byte(event.Details), &details))
		require.Equal(t, grant.ID, details["grant_id"])
		require.Equal(t, "user", details["subject_type"])
		require.Equal(t, "viewer", details["subject_id"])
		require.Equal(t, source.ID, details["source_id"])
		require.Equal(t, reposstore.RepoRolePrimary, details["repo_role"])
		require.NotContains(t, event.Details, "repo_full_name")
		switch event.Action {
		case "kb.repository_access.override.grant":
			found[event.Action] = true
			require.Equal(t, "inherit", details["previous_profile"])
			require.Equal(t, "manage", details["profile"])
		case "kb.repository_access.override.update":
			found[event.Action] = true
			require.Equal(t, "manage", details["previous_profile"])
			require.Equal(t, "read", details["profile"])
		case "kb.repository_access.override.delete":
			found[event.Action] = true
			require.Equal(t, "read", details["previous_profile"])
			require.Equal(t, "inherit", details["profile"])
		}
	}
	require.True(t, found["kb.repository_access.override.grant"])
	require.True(t, found["kb.repository_access.override.update"])
	require.True(t, found["kb.repository_access.override.delete"])
}

func TestKBServicePreservesMaterializedRepositoryAccessStateWhenUpdateFails(t *testing.T) {
	ctx := context.Background()
	svc := newKBServiceForTest(t)
	wikiStore := svc.wikiStore.(*fakeAGSRepositoryStore)
	base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
	require.NoError(t, err)
	_, err = svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
	require.NoError(t, err)
	writeProfile := kb.KnowledgeBaseRepositoryAccessProfileWrite
	grant, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{SubjectType: "user", SubjectID: "viewer", Role: "edit", RepositoryAccessProfile: &writeProfile})
	require.NoError(t, err)
	wikiStore.grants = nil
	wikiStore.grantErr = errors.New("ags unavailable")
	readProfile := kb.KnowledgeBaseRepositoryAccessProfileRead

	updated, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{GrantID: grant.ID, RepositoryAccessProfile: &readProfile})
	require.NoError(t, err)
	require.Equal(t, kb.KnowledgeBaseRepositoryAccessProfileRead, updated.RepositoryAccessProfile)
	require.Equal(t, kbRepositoryAccessStatusBlocked, updated.RepositoryAccessStatus)
	require.Equal(t, "ags unavailable", updated.RepositoryAccessLastError)
	require.Len(t, wikiStore.grants, 2)
	for _, request := range wikiStore.grants {
		require.Equal(t, reposstore.AccessPermissionRead, request.Permission)
		require.True(t, request.AllowExistingDirectUpdate)
	}

	rows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, grant.ID)
	require.NoError(t, err)
	require.Len(t, rows, 2)
	for _, row := range rows {
		require.Equal(t, reposstore.AccessPermissionWrite, row.Permission)
		require.True(t, row.Materialized)
		require.Equal(t, reposstore.AccessStatusBlocked, row.Status)
		require.Equal(t, "ags unavailable", row.LastError)
	}
}

func TestKBServiceAuditsRepositoryAccessProfileAndReconciliation(t *testing.T) {
	ctx := context.Background()
	svc := newKBServiceForTest(t)
	base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
	require.NoError(t, err)
	_, err = svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
	require.NoError(t, err)
	readProfile := kb.KnowledgeBaseRepositoryAccessProfileRead

	grant, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{SubjectType: "user", SubjectID: "viewer", Role: "view", RepositoryAccessProfile: &readProfile})
	require.NoError(t, err)
	require.Equal(t, kbRepositoryAccessStatusCurrent, grant.RepositoryAccessStatus)

	events, err := svc.ListAuditEvents(ctx, "wsp_1", "owner", base.ID, 1, 50)
	require.NoError(t, err)
	profileEventFound := false
	reconcileEvents := 0
	reconciledRoles := make(map[string]bool)
	for _, event := range events {
		switch event.Action {
		case "kb.repository_access.grant":
			if event.ResourceID != grant.ID {
				continue
			}
			profileEventFound = true
			require.Equal(t, "permission_grant", event.ResourceType)
			var details map[string]any
			require.NoError(t, json.Unmarshal([]byte(event.Details), &details))
			require.Equal(t, "none", details["previous_profile"])
			require.Equal(t, "read", details["profile"])
			require.Equal(t, "current", details["status"])
		case "kb.repository_access.reconcile":
			var details map[string]any
			require.NoError(t, json.Unmarshal([]byte(event.Details), &details))
			if details["subject_id"] != "viewer" {
				continue
			}
			reconcileEvents++
			require.Equal(t, "repository_access", event.ResourceType)
			require.NotContains(t, event.Details, "repo_full_name")
			require.NotEmpty(t, details["source_id"])
			repoRole, _ := details["repo_role"].(string)
			require.Contains(t, []string{reposstore.RepoRolePrimary, reposstore.RepoRoleInsights}, repoRole)
			reconciledRoles[repoRole] = true
			require.Equal(t, "current", details["status"])
		}
	}
	require.True(t, profileEventFound)
	require.Equal(t, 2, reconcileEvents)
	require.True(t, reconciledRoles[reposstore.RepoRolePrimary])
	require.True(t, reconciledRoles[reposstore.RepoRoleInsights])
}

func TestKBServiceCreateSourceRepairsNewSourceWithoutRevokingExistingGrantRows(t *testing.T) {
	ctx := context.Background()
	svc := newKBServiceForTest(t)
	wikiStore := svc.wikiStore.(*fakeAGSRepositoryStore)
	base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
	require.NoError(t, err)
	firstSource, err := svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
	require.NoError(t, err)
	readProfile := kb.KnowledgeBaseRepositoryAccessProfileRead
	viewer, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{SubjectType: "user", SubjectID: "viewer", Role: "view", RepositoryAccessProfile: &readProfile})
	require.NoError(t, err)
	wikiStore.grants = nil
	wikiStore.revokes = nil

	secondSource, err := svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "PD", IndexStatus: "ready"})
	require.NoError(t, err)
	require.Empty(t, wikiStore.revokes)

	rows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, viewer.ID)
	require.NoError(t, err)
	require.Len(t, rows, 4)
	currentBySource := map[string]int{}
	for _, row := range rows {
		require.Equal(t, reposstore.AccessStatusCurrent, row.Status)
		require.True(t, row.Materialized)
		currentBySource[row.ResourceID]++
	}
	require.Equal(t, 2, currentBySource[firstSource.ID])
	require.Equal(t, 2, currentBySource[secondSource.ID])
}

func TestKBServiceRepairRepositoryAccessDoesNotRevokeRowsOutsideRepairSet(t *testing.T) {
	ctx := context.Background()
	svc := newKBServiceForTest(t)
	wikiStore := svc.wikiStore.(*fakeAGSRepositoryStore)
	base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
	require.NoError(t, err)
	firstSource, err := svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
	require.NoError(t, err)
	secondSource, err := svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "PD", IndexStatus: "ready"})
	require.NoError(t, err)
	readProfile := kb.KnowledgeBaseRepositoryAccessProfileRead
	viewer, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{SubjectType: "user", SubjectID: "viewer", Role: "view", RepositoryAccessProfile: &readProfile})
	require.NoError(t, err)
	storeGrant, err := svc.store.GetKnowledgeBaseGrantByID(ctx, "wsp_1", base.ID, viewer.ID)
	require.NoError(t, err)
	secondRepos, err := svc.repositoryStore.ListForResource(ctx, "wsp_1", reposstore.ResourceTypeKBSource, secondSource.ID)
	require.NoError(t, err)
	wikiStore.revokes = nil

	require.NoError(t, svc.repairKnowledgeBaseGrantRepositoryAccessForRepositories(ctx, storeGrant, secondRepos, "owner"))
	require.Empty(t, wikiStore.revokes)

	rows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, viewer.ID)
	require.NoError(t, err)
	currentBySource := map[string]int{}
	for _, row := range rows {
		require.Equal(t, reposstore.AccessStatusCurrent, row.Status)
		currentBySource[row.ResourceID]++
	}
	require.Equal(t, 2, currentBySource[firstSource.ID])
	require.Equal(t, 2, currentBySource[secondSource.ID])
}

func TestKBServiceRepairRepositoryAccessUsesStrongerIndependentPermission(t *testing.T) {
	ctx := context.Background()
	svc := newKBServiceForTest(t)
	wikiStore := svc.wikiStore.(*fakeAGSRepositoryStore)
	base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
	require.NoError(t, err)
	source, err := svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
	require.NoError(t, err)
	readProfile := kb.KnowledgeBaseRepositoryAccessProfileRead
	viewer, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{SubjectType: "user", SubjectID: "viewer", Role: "view", RepositoryAccessProfile: &readProfile})
	require.NoError(t, err)
	rows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, viewer.ID)
	require.NoError(t, err)
	require.Len(t, rows, 2)
	upsertSiblingRepositoryAccessIntent(t, ctx, svc, rows, "kbg_admin_intent", reposstore.AccessPermissionAdmin, true)
	for _, row := range rows {
		row.Materialized = false
		row.Status = reposstore.AccessStatusBlocked
		row.LastError = "legacy blocked row"
		_, err := svc.repositoryStore.UpsertAccessGrant(ctx, row)
		require.NoError(t, err)
	}
	storeGrant, err := svc.store.GetKnowledgeBaseGrantByID(ctx, "wsp_1", base.ID, viewer.ID)
	require.NoError(t, err)
	repos, err := svc.repositoryStore.ListForResource(ctx, "wsp_1", reposstore.ResourceTypeKBSource, source.ID)
	require.NoError(t, err)
	wikiStore.grants = nil

	require.NoError(t, svc.repairKnowledgeBaseGrantRepositoryAccessForRepositories(ctx, storeGrant, repos, "owner"))
	require.Len(t, wikiStore.grants, 2)
	for _, request := range wikiStore.grants {
		require.Equal(t, reposstore.AccessPermissionAdmin, request.Permission)
		require.True(t, request.AllowExistingDirectUpdate)
	}

	repairedRows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, viewer.ID)
	require.NoError(t, err)
	require.Len(t, repairedRows, 2)
	for _, row := range repairedRows {
		require.Equal(t, reposstore.AccessPermissionRead, row.Permission)
		require.True(t, row.Materialized)
		require.Equal(t, reposstore.AccessStatusCurrent, row.Status)
		require.Empty(t, row.LastError)
	}
}

func TestKBServiceRepairRepositoryAccessRespectsNoneProfileAndOverrides(t *testing.T) {
	t.Run("profile none creates no repair grants", func(t *testing.T) {
		ctx := context.Background()
		svc := newKBServiceForTest(t)
		wikiStore := svc.wikiStore.(*fakeAGSRepositoryStore)
		base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
		require.NoError(t, err)
		source, err := svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
		require.NoError(t, err)
		noneProfile := kb.KnowledgeBaseRepositoryAccessProfileNone
		viewer, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{SubjectType: "user", SubjectID: "viewer", Role: "view", RepositoryAccessProfile: &noneProfile})
		require.NoError(t, err)
		storeGrant, err := svc.store.GetKnowledgeBaseGrantByID(ctx, "wsp_1", base.ID, viewer.ID)
		require.NoError(t, err)
		repos, err := svc.repositoryStore.ListForResource(ctx, "wsp_1", reposstore.ResourceTypeKBSource, source.ID)
		require.NoError(t, err)
		wikiStore.grants = nil

		require.NoError(t, svc.repairKnowledgeBaseGrantRepositoryAccessForRepositories(ctx, storeGrant, repos, "owner"))
		require.Empty(t, wikiStore.grants)
		rows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, viewer.ID)
		require.NoError(t, err)
		require.Empty(t, rows)
	})

	t.Run("override none excludes that source repository from repair", func(t *testing.T) {
		ctx := context.Background()
		svc := newKBServiceForTest(t)
		wikiStore := svc.wikiStore.(*fakeAGSRepositoryStore)
		base, err := svc.CreateKnowledgeBase(ctx, "wsp_1", "owner", KBMutation{Name: "Runbooks"})
		require.NoError(t, err)
		source, err := svc.CreateSource(ctx, "wsp_1", "owner", base.ID, KBSourceMutation{SourceType: "codebase", Name: "TiDB", IndexStatus: "ready"})
		require.NoError(t, err)
		writeProfile := kb.KnowledgeBaseRepositoryAccessProfileWrite
		viewer, err := svc.UpsertKnowledgeBasePermission(ctx, "wsp_1", "owner", base.ID, KBPermissionGrantMutation{SubjectType: "user", SubjectID: "viewer", Role: "edit", RepositoryAccessProfile: &writeProfile})
		require.NoError(t, err)
		noneProfile := kb.KnowledgeBaseRepositoryAccessProfileNone
		_, err = svc.UpdateKnowledgeBasePermissionRepositoryOverrides(ctx, "wsp_1", "owner", base.ID, viewer.ID, []KBPermissionRepositoryOverrideMutation{{SourceID: source.ID, RepoRole: reposstore.RepoRolePrimary, RepositoryAccessProfile: &noneProfile}})
		require.NoError(t, err)
		rows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, viewer.ID)
		require.NoError(t, err)
		for _, row := range rows {
			if row.RepoRole != reposstore.RepoRoleInsights {
				continue
			}
			row.Materialized = false
			row.Status = reposstore.AccessStatusBlocked
			row.LastError = "legacy blocked row"
			_, err := svc.repositoryStore.UpsertAccessGrant(ctx, row)
			require.NoError(t, err)
		}
		storeGrant, err := svc.store.GetKnowledgeBaseGrantByID(ctx, "wsp_1", base.ID, viewer.ID)
		require.NoError(t, err)
		repos, err := svc.repositoryStore.ListForResource(ctx, "wsp_1", reposstore.ResourceTypeKBSource, source.ID)
		require.NoError(t, err)
		wikiStore.grants = nil

		require.NoError(t, svc.repairKnowledgeBaseGrantRepositoryAccessForRepositories(ctx, storeGrant, repos, "owner"))
		require.Len(t, wikiStore.grants, 1)
		require.Equal(t, "owner/tidb.kb", wikiStore.grants[0].Repository.FullName)
		require.Equal(t, reposstore.AccessPermissionWrite, wikiStore.grants[0].Permission)

		repairedRows, err := svc.repositoryStore.ListAccessGrantsForIntent(ctx, "wsp_1", reposstore.AccessIntentTypeKBGrant, viewer.ID)
		require.NoError(t, err)
		rowsByRole := map[string]reposstore.ResourceRepositoryAccessGrant{}
		for _, row := range repairedRows {
			rowsByRole[row.RepoRole] = row
		}
		require.Equal(t, reposstore.AccessStatusRevoked, rowsByRole[reposstore.RepoRolePrimary].Status)
		require.Equal(t, reposstore.AccessStatusCurrent, rowsByRole[reposstore.RepoRoleInsights].Status)
	})
}

func sourceRepositoryAccessForRole(t *testing.T, rows []KBPermissionRepositoryAccess, repoRole string) KBPermissionRepositoryAccess {
	t.Helper()
	for _, row := range rows {
		if row.RepoRole == repoRole {
			return row
		}
	}
	t.Fatalf("missing source repository access row for role %q", repoRole)
	return KBPermissionRepositoryAccess{}
}

func upsertRepositoryAccessIntent(t *testing.T, ctx context.Context, svc *KBService, repos []reposstore.ResourceRepository, subjectID, intentID, permission, profile string, materialized bool) {
	t.Helper()
	for _, repo := range eligibleHumanRepositoryAccessRepos(repos) {
		_, err := svc.repositoryStore.UpsertAccessGrant(ctx, reposstore.ResourceRepositoryAccessGrant{
			WorkspaceID:   repo.WorkspaceID,
			ResourceType:  repo.ResourceType,
			ResourceID:    repo.ResourceID,
			RepoRole:      repo.RepoRole,
			RepoFullName:  repo.RepoFullName,
			AGSRepoID:     repo.AGSRepoID,
			SubjectType:   "user",
			SubjectID:     subjectID,
			Permission:    permission,
			IntentType:    reposstore.AccessIntentTypeKBGrant,
			IntentID:      intentID,
			IntentProfile: profile,
			Materialized:  materialized,
			Status:        reposstore.AccessStatusCurrent,
			CreatedBy:     "owner",
			UpdatedBy:     "owner",
			CreatedAt:     svc.now(),
			UpdatedAt:     svc.now(),
		})
		require.NoError(t, err)
	}
}
