package packs

import (
	"context"
	"strings"
	"testing"

	"github.com/DATA-DOG/go-sqlmock"
	"github.com/nexuscrm/kernel/pkg/flowactions"
	connector "github.com/pingcap-inc/nexuscrm-contract/pkg/connector"
	cp "github.com/pingcap-inc/nexuscrm-contract/pkg/controlplane"
)

func testRuntimeStartupShallowRegistrationSet(t *testing.T) ComponentKindRegistrationSet {
	t.Helper()
	set, err := NewComponentKindRegistrationSet([]cp.ComponentKindRegistration{
		testComponentKindRegistration(cp.ComponentKindApprovalProcess, "ProcessDefinition"),
	})
	if err != nil {
		t.Fatal(err)
	}
	return set
}

func mustRuntimeStartupShallowProjectionJSON(t *testing.T, v any) string {
	t.Helper()
	raw, err := marshalRuntimeStartupShallowProjection(v)
	if err != nil {
		t.Fatalf("marshalRuntimeStartupShallowProjection: %v", err)
	}
	return raw
}

func mustRuntimeStartupShallowDeclarationJSON(t *testing.T, rows []runtimeStartupShallowDeclaredRow) string {
	t.Helper()
	raw, err := marshalRuntimeStartupShallowDeclaredRows(rows)
	if err != nil {
		t.Fatalf("marshalRuntimeStartupShallowDeclaredRows: %v", err)
	}
	return raw
}

func mustValidationRuleStartupShallowProjectionJSON(t *testing.T, objectAPIName, name string, active bool, condition, errorMessage string) string {
	t.Helper()
	return mustRuntimeStartupShallowProjectionJSON(t, runtimeStartupShallowValidationRuleProjection{
		ObjectAPIName: objectAPIName,
		Name:          name,
		Active:        active,
		Condition:     condition,
		ErrorMessage:  errorMessage,
		OwnerPack:     "crm-pack",
	})
}

func expectValidationRuleStartupShallowProjectionQuery(mock sqlmock.Sqlmock, ownerPack, objectAPIName, name, rowPredicate string, active bool, condition, errorMessage string, isCustomized bool) {
	mock.ExpectQuery("SELECT ObjectApiName, Name, Description, Active, `Condition`, ErrorMessage, ErrorDisplayField, RecordSetBindings, IsCustomized, OwnerPack\\s+FROM _System_ValidationRule\\s+WHERE COALESCE\\(OwnerPack, ''\\) = \\?\\s+AND ObjectApiName = \\?\\s+AND Name = \\?\\s+AND "+rowPredicate+"\\s+LIMIT 1").
		WithArgs(ownerPack, objectAPIName, name).
		WillReturnRows(sqlmock.NewRows([]string{
			"ObjectApiName", "Name", "Description", "Active", "Condition", "ErrorMessage", "ErrorDisplayField", "RecordSetBindings", "IsCustomized", "OwnerPack",
		}).AddRow(objectAPIName, name, nil, active, condition, errorMessage, nil, nil, isCustomized, ownerPack))
}

func expectValidationRuleStartupShallowExistenceQuery(mock sqlmock.Sqlmock, ownerPack, objectAPIName, name, rowPredicate string) {
	mock.ExpectQuery("SELECT 1\\s+FROM _System_ValidationRule\\s+WHERE COALESCE\\(OwnerPack, ''\\) = \\?\\s+AND ObjectApiName = \\?\\s+AND Name = \\?\\s+AND "+rowPredicate+"\\s+LIMIT 1").
		WithArgs(ownerPack, objectAPIName, name).
		WillReturnRows(sqlmock.NewRows([]string{"1"}).AddRow(1))
}

func expectValidationRuleStartupShallowDeclaredRowPredicateActive(mock sqlmock.Sqlmock) {
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
}

func expectValidationRuleStartupShallowDeclaredRowPredicateIsDeleted(mock sqlmock.Sqlmock) {
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(0))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "IsDeleted").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
}

const validationRuleStartupShallowLegacyRetainedCustomizedPredicate = "\\(COALESCE\\(IsDeleted, 0\\) = 0 OR COALESCE\\(IsCustomized, 0\\) = 1\\)"

func expectRuntimeStartupShallowDeclarationQuery(mock sqlmock.Sqlmock, packName string, payload string) {
	mock.ExpectQuery("SELECT RuntimeStartupShallowDeclarations").
		WithArgs(packName).
		WillReturnRows(sqlmock.NewRows([]string{"RuntimeStartupShallowDeclarations"}).AddRow(payload))
}

func expectRuntimeObjectSpecDeclarationQuery(mock sqlmock.Sqlmock, packName string, payload string) {
	mock.ExpectQuery("SELECT RuntimeObjectSpecDeclarations").
		WithArgs(packName).
		WillReturnRows(sqlmock.NewRows([]string{"RuntimeObjectSpecDeclarations"}).AddRow(payload))
}

func expectUIActionStartupShallowQuery(mock sqlmock.Sqlmock, packName string) *sqlmock.ExpectedQuery {
	return mock.ExpectQuery("SELECT ObjectApiName, Name\\s+FROM _System_Action").
		WithArgs(packName)
}

func expectFlowActionCallHandlerStartupShallowQuery(mock sqlmock.Sqlmock, packName string) *sqlmock.ExpectedQuery {
	return mock.ExpectQuery("SELECT ActionType\\s+FROM _System_FlowActionCallHandler").
		WithArgs(packName)
}

func expectEmptyAppPackStartupShallowSupportedScans(mock sqlmock.Sqlmock, packName string, except ...ComponentKind) {
	skip := map[ComponentKind]bool{}
	for _, kind := range except {
		skip[kind] = true
	}
	expectRuntimeObjectSpecDeclarationQuery(mock, packName, `[]`)
	if !skip[ComponentKindPermission] {
		mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
			WithArgs(packName).
			WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	}
	if !skip[ComponentKindValidationRule] {
		mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
			WithArgs("_System_ValidationRule", "Active").
			WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
		mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
			WithArgs(packName).
			WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}))
	}
	if !skip[ComponentKindInvocableAction] {
		mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
			WithArgs(packName).
			WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	}
	if !skip[ComponentKindFlowActionCallHandler] {
		expectFlowActionCallHandlerStartupShallowQuery(mock, packName).
			WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	}
	if !skip[ComponentKindReportType] {
		mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
			WithArgs(packName).
			WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	}
	if !skip[ComponentKindUIAction] {
		expectUIActionStartupShallowQuery(mock, packName).
			WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	}
	if !skip[ComponentKindStandardFlow] {
		mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
			WithArgs(packName).
			WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	}
	if !skip[ComponentKindFieldMapping] {
		mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
			WithArgs(packName).
			WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	}
	if !skip[ComponentKindAutoNumberFormat] {
		mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
			WithArgs(packName).
			WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	}
	if !skip[ComponentKindRecordType] {
		expectRecordTypeStartupShallowScan(mock, packName).
			WillReturnRows(recordTypeStartupShallowRows())
	}
}

func recordTypeStartupShallowProjection(objectAPIName, name, ownerPack string) sourceBackedRecordTypeRow {
	return sourceBackedRecordTypeRow{
		ObjectAPIName: objectAPIName,
		Name:          name,
		DeveloperName: canonicalSourceBackedRecordTypeDeveloperName(name, ""),
		SobjectType:   objectAPIName,
		IsActive:      true,
		IsMaster:      false,
		OwnerPack:     ownerPack,
	}
}

func recordTypeStartupShallowRows(rows ...sourceBackedRecordTypeRow) *sqlmock.Rows {
	out := sqlmock.NewRows([]string{"ApiName", "Name", "DeveloperName"})
	for _, row := range rows {
		out.AddRow(row.ObjectAPIName, row.Name, row.DeveloperName)
	}
	return out
}

func expectRecordTypeStartupShallowScan(mock sqlmock.Sqlmock, packName string) *sqlmock.ExpectedQuery {
	return mock.ExpectQuery("SELECT o\\.ApiName, rt\\.Name, COALESCE\\(rt\\.DeveloperName, ''\\)\\s+FROM _System_RecordType rt").
		WithArgs(packName)
}

func expectRecordTypeStartupShallowProjectionQuery(mock sqlmock.Sqlmock, objectAPIName, developerName, name string, row sourceBackedRecordTypeRow) {
	mock.ExpectQuery("SELECT o\\.ApiName, rt\\.Name, COALESCE\\(rt\\.DeveloperName, ''\\), COALESCE\\(rt\\.SobjectType, ''\\), rt\\.record_type_code, rt\\.IsActive, rt\\.IsMaster, rt\\.BusinessProcessId, COALESCE\\(rt\\.OwnerPack, ''\\), rt\\.IsDeleted\\s+FROM _System_RecordType rt").
		WithArgs(objectAPIName, developerName, name, developerName).
		WillReturnRows(sqlmock.NewRows([]string{
			"ApiName", "Name", "DeveloperName", "SobjectType", "record_type_code", "IsActive", "IsMaster", "BusinessProcessId", "OwnerPack", "IsDeleted",
		}).AddRow(
			row.ObjectAPIName, row.Name, row.DeveloperName, row.SobjectType, nil, row.IsActive, row.IsMaster, nil, row.OwnerPack, false,
		))
}

func expectEmptyConnectorPackStartupShallowSupportedScans(mock sqlmock.Sqlmock, packName string, except ...ComponentKind) {
	skip := map[ComponentKind]bool{}
	for _, kind := range except {
		skip[kind] = true
	}
	if !skip[ComponentKindConnectorCapability] {
		mock.ExpectQuery("SELECT Namespace, Kind\\s+FROM _System_ConnectorCapabilityDeclaration").
			WithArgs(packName).
			WillReturnRows(sqlmock.NewRows([]string{"Namespace", "Kind"}))
	}
	if !skip[ComponentKindWebhookSecret] {
		mock.ExpectQuery("SELECT Name\\s+FROM _System_WebhookSecret").
			WithArgs(strings.ToLower(packName)).
			WillReturnRows(sqlmock.NewRows([]string{"Name"}))
	}
	if !skip[ComponentKindConnectorRateLimit] {
		mock.ExpectQuery("SELECT EndpointClass\\s+FROM _System_ConnectorRateLimit").
			WithArgs(strings.ToLower(packName)).
			WillReturnRows(sqlmock.NewRows([]string{"EndpointClass"}))
	}
	if !skip[ComponentKindConnectorCalloutProfile] {
		mock.ExpectQuery("SELECT ProfileName\\s+FROM _System_ConnectorCalloutProfile").
			WithArgs(packName).
			WillReturnRows(sqlmock.NewRows([]string{"ProfileName"}))
	}
	if !skip[ComponentKindConnectorInboundHandlerConfig] {
		mock.ExpectQuery("SELECT CapabilityKind\\s+FROM _System_ConnectorInboundHandlerConfig").
			WithArgs(packName).
			WillReturnRows(sqlmock.NewRows([]string{"CapabilityKind"}))
	}
	if !skip[ComponentKindConnectorInboundRoute] {
		mock.ExpectQuery("SELECT r.EventKind\\s+FROM _System_ConnectorInboundRoute r\\s+JOIN _System_InstalledPack p ON p.PackInstallId = r.InstalledPackId").
			WithArgs(packName, packName).
			WillReturnRows(sqlmock.NewRows([]string{"EventKind"}))
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameAcceptsMatchingConnectorDeclaration(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "test-connector", `[{"kind":"connector_capability","businessKey":"test-connector:signature_verifier"}]`)
	mock.ExpectQuery("SELECT Namespace, Kind\\s+FROM _System_ConnectorCapabilityDeclaration").
		WithArgs("test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"Namespace", "Kind"}).AddRow("test-connector", "signature_verifier"))
	expectEmptyConnectorPackStartupShallowSupportedScans(mock, "test-connector", ComponentKindConnectorCapability)

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "test-connector", ConnectorPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameAcceptsConnectorFieldMappingDeclaration(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "test-connector", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindFieldMapping, BusinessKey: "Contact/Person/syncContact/email/bidirectional"},
		{Kind: ComponentKindFieldMapping, BusinessKey: "Contact/Person/syncContact/email/inbound"},
	}))
	expectEmptyConnectorPackStartupShallowSupportedScans(mock, "test-connector")
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}).
			AddRow("Contact", "Person", "syncContact", "email", "bidirectional", false).
			AddRow("Contact", "Person", "syncContact", "email", "inbound", false))

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "test-connector", ConnectorPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameBindsConnectorFieldMappingToInstalledOwner(t *testing.T) {
	projection := func(t *testing.T, source string) string {
		t.Helper()
		return mustRuntimeStartupShallowProjectionJSON(t, []connector.ConnectorFieldMappingInput{{
			Source: source, SourceObject: "RemoteContact", TargetObject: "Contact",
			ActionType: "upsert", SourceField: "email", TargetField: "Email",
			Direction: connector.DirectionInbound,
		}})
	}

	tests := []struct {
		name             string
		projectionSource string
		wantError        string
	}{
		{
			name:             "case-variant business key uses installed owner",
			projectionSource: "sample-connector",
		},
		{
			name:             "case-variant projection source fails closed",
			projectionSource: "Sample-Connector",
			wantError:        `owner "Sample-Connector" disagrees with "sample-connector"`,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			db, mock, err := sqlmock.New()
			if err != nil {
				t.Fatalf("sqlmock: %v", err)
			}
			defer db.Close()

			expectRuntimeStartupShallowDeclarationQuery(mock, "sample-connector", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{{
				Kind: ComponentKindConnectorFieldMapping, BusinessKey: "Sample-Connector/contact-sync",
				Projection: projection(t, test.projectionSource),
			}}))
			expectEmptyConnectorPackStartupShallowSupportedScans(mock, "sample-connector")

			err = VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "sample-connector", ConnectorPack)
			if test.wantError == "" {
				if err != nil {
					t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
				}
			} else if err == nil || !strings.Contains(err.Error(), test.wantError) {
				t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName error = %v, want containing %q", err, test.wantError)
			}
			if err := mock.ExpectationsWereMet(); err != nil {
				t.Fatalf("sql expectations: %v", err)
			}
		})
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameFailsClosedForUndeclaredConnectorLiveRow(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "test-connector", "[]")
	expectEmptyConnectorPackStartupShallowSupportedScans(mock, "test-connector")
	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "test-connector", ConnectorPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName empty declaration: %v", err)
	}

	db2, mock2, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock second db: %v", err)
	}
	defer db2.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock2, "test-connector", `[{"kind":"connector_capability","businessKey":"test-connector:signature_verifier"}]`)
	mock2.ExpectQuery("SELECT Namespace, Kind\\s+FROM _System_ConnectorCapabilityDeclaration").
		WithArgs("test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"Namespace", "Kind"}))
	expectEmptyConnectorPackStartupShallowSupportedScans(mock2, "test-connector", ComponentKindConnectorCapability)

	err = VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db2, "test-connector", ConnectorPack)
	if err == nil || err.Error() == "" {
		t.Fatal("VerifyInstalledPersistedRuntimeShallowByName = nil, want drift error")
	}
	if err == nil || !strings.Contains(err.Error(), "connector_capability test-connector:signature_verifier is missing") {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName error = %v, want missing connector capability", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations first db: %v", err)
	}
	if err := mock2.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations second db: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameAcceptsConnectorInboundBareKeys(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "test-connector", `[
{"kind":"connector_inbound_handler_config","businessKey":"signature_verifier"},
{"kind":"connector_inbound_route","businessKey":"ticket.created"}
]`)
	mock.ExpectQuery("SELECT Namespace, Kind\\s+FROM _System_ConnectorCapabilityDeclaration").
		WithArgs("test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"Namespace", "Kind"}))
	mock.ExpectQuery("SELECT Name\\s+FROM _System_WebhookSecret").
		WithArgs("test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"Name"}))
	mock.ExpectQuery("SELECT EndpointClass\\s+FROM _System_ConnectorRateLimit").
		WithArgs("test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"EndpointClass"}))
	mock.ExpectQuery("SELECT ProfileName\\s+FROM _System_ConnectorCalloutProfile").
		WithArgs("test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"ProfileName"}))
	mock.ExpectQuery("SELECT CapabilityKind\\s+FROM _System_ConnectorInboundHandlerConfig").
		WithArgs("test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"CapabilityKind"}).AddRow("signature_verifier"))
	mock.ExpectQuery("SELECT r.EventKind\\s+FROM _System_ConnectorInboundRoute r\\s+JOIN _System_InstalledPack p ON p.PackInstallId = r.InstalledPackId").
		WithArgs("test-connector", "test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"EventKind"}).AddRow("ticket.created"))

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "test-connector", ConnectorPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameScopesConnectorInboundRoutesToActiveIncarnation(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "test-connector", `[{"kind":"connector_inbound_route","businessKey":"ticket.created"}]`)
	mock.ExpectQuery("SELECT Namespace, Kind\\s+FROM _System_ConnectorCapabilityDeclaration").
		WithArgs("test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"Namespace", "Kind"}))
	mock.ExpectQuery("SELECT Name\\s+FROM _System_WebhookSecret").
		WithArgs("test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"Name"}))
	mock.ExpectQuery("SELECT EndpointClass\\s+FROM _System_ConnectorRateLimit").
		WithArgs("test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"EndpointClass"}))
	mock.ExpectQuery("SELECT ProfileName\\s+FROM _System_ConnectorCalloutProfile").
		WithArgs("test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"ProfileName"}))
	mock.ExpectQuery("SELECT CapabilityKind\\s+FROM _System_ConnectorInboundHandlerConfig").
		WithArgs("test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"CapabilityKind"}))
	mock.ExpectQuery("SELECT r.EventKind\\s+FROM _System_ConnectorInboundRoute r\\s+JOIN _System_InstalledPack p ON p.PackInstallId = r.InstalledPackId").
		WithArgs("test-connector", "test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"EventKind"}).AddRow("ticket.created"))

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "test-connector", ConnectorPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameNormalizesWebhookSecretOwnerPack(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "Test-Connector", `[{"kind":"webhook_secret","businessKey":"orders"}]`)
	mock.ExpectQuery("SELECT Namespace, Kind\\s+FROM _System_ConnectorCapabilityDeclaration").
		WithArgs("Test-Connector").
		WillReturnRows(sqlmock.NewRows([]string{"Namespace", "Kind"}))
	mock.ExpectQuery("SELECT Name\\s+FROM _System_WebhookSecret").
		WithArgs("test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"Name"}).AddRow("orders"))
	mock.ExpectQuery("SELECT EndpointClass\\s+FROM _System_ConnectorRateLimit").
		WithArgs("test-connector").
		WillReturnRows(sqlmock.NewRows([]string{"EndpointClass"}))
	mock.ExpectQuery("SELECT ProfileName\\s+FROM _System_ConnectorCalloutProfile").
		WithArgs("Test-Connector").
		WillReturnRows(sqlmock.NewRows([]string{"ProfileName"}))
	mock.ExpectQuery("SELECT CapabilityKind\\s+FROM _System_ConnectorInboundHandlerConfig").
		WithArgs("Test-Connector").
		WillReturnRows(sqlmock.NewRows([]string{"CapabilityKind"}))
	mock.ExpectQuery("SELECT r.EventKind\\s+FROM _System_ConnectorInboundRoute r\\s+JOIN _System_InstalledPack p ON p.PackInstallId = r.InstalledPackId").
		WithArgs("Test-Connector", "Test-Connector").
		WillReturnRows(sqlmock.NewRows([]string{"EventKind"}))

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "Test-Connector", ConnectorPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameAcceptsLegacyMissingRecordTypeProjectionFromSourceIdentity(t *testing.T) {
	registrations := testRuntimeStartupShallowRegistrationSet(t)
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expected := recordTypeStartupShallowProjection("Account", "Contract Only (APAC)", "crm-pack")
	projection := mustRuntimeStartupShallowProjectionJSON(t, expected)
	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", `[]`)
	expectEmptyAppPackStartupShallowSupportedScans(mock, "crm-pack", ComponentKindRecordType)
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows(expected))
	mock.ExpectQuery("SELECT AppliedPayloadHash, ManifestFormatVersion, SourceKind, SourceURI, SourceRevision\\s+FROM _System_InstalledPack").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"AppliedPayloadHash", "ManifestFormatVersion", "SourceKind", "SourceURI", "SourceRevision"}).
			AddRow("hash-123", SupportedManifestFormatVersion, string(PackSourceKindLocalPath), "/tmp/crm-pack", nil))
	expectRecordTypeStartupShallowProjectionQuery(mock, "Account", "Contract_Only_APAC", "Contract Only (APAC)", expected)

	originalResolveInstalledPack := resolveInstalledPackForStartupShallowCompat
	resolveInstalledPackForStartupShallowCompat = func(input InstalledPackResolverInput, opts InstalledPackResolverOptions) (Pack, error) {
		if input.AppliedPayloadHash != "hash-123" {
			t.Fatalf("AppliedPayloadHash = %q, want hash-123", input.AppliedPayloadHash)
		}
		if input.SourceKind != string(PackSourceKindLocalPath) {
			t.Fatalf("SourceKind = %q, want %q", input.SourceKind, string(PackSourceKindLocalPath))
		}
		if input.SourceURI != "/tmp/crm-pack" {
			t.Fatalf("SourceURI = %q, want /tmp/crm-pack", input.SourceURI)
		}
		if opts.ComponentKindRegistrationSet == nil || len(opts.ComponentKindRegistrationSet.Registrations()) != 1 {
			t.Fatal("legacy projection fallback did not receive the registration snapshot")
		}
		return runtimeStartupShallowDeclaredCompatPack{
			rows: []runtimeStartupShallowDeclaredRow{{Kind: ComponentKindRecordType, BusinessKey: JoinComponentBusinessKey("Account", "Contract_Only_APAC"), Projection: projection}},
		}, nil
	}
	defer func() { resolveInstalledPackForStartupShallowCompat = originalResolveInstalledPack }()

	if err := VerifyInstalledPersistedRuntimeShallowByNameWithComponentKindRegistrationSet(context.Background(), db, "crm-pack", AppPack, registrations); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameRejectsLegacyMissingRecordTypeWithoutPayloadHash(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expected := recordTypeStartupShallowProjection("Account", "Contract Only (APAC)", "crm-pack")
	projection := mustRuntimeStartupShallowProjectionJSON(t, expected)
	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", `[]`)
	expectEmptyAppPackStartupShallowSupportedScans(mock, "crm-pack", ComponentKindRecordType)
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows(expected))
	mock.ExpectQuery("SELECT AppliedPayloadHash, ManifestFormatVersion, SourceKind, SourceURI, SourceRevision\\s+FROM _System_InstalledPack").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"AppliedPayloadHash", "ManifestFormatVersion", "SourceKind", "SourceURI", "SourceRevision"}).
			AddRow("", SupportedManifestFormatVersion, string(PackSourceKindLocalPath), "/tmp/crm-pack", nil))

	originalResolveInstalledPack := resolveInstalledPackForStartupShallowCompat
	resolveInstalledPackForStartupShallowCompat = func(input InstalledPackResolverInput, opts InstalledPackResolverOptions) (Pack, error) {
		return runtimeStartupShallowDeclaredCompatPack{
			rows: []runtimeStartupShallowDeclaredRow{{Kind: ComponentKindRecordType, BusinessKey: JoinComponentBusinessKey("Account", "Contract_Only_APAC"), Projection: projection}},
		}, nil
	}
	defer func() { resolveInstalledPackForStartupShallowCompat = originalResolveInstalledPack }()

	err = VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack)
	if err == nil || !strings.Contains(err.Error(), "source identity missing required hash-gated fields") {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName error = %v, want missing hash fail closed", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameRejectsRecordTypeBlankProjection(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expected := recordTypeStartupShallowProjection("Account", "Contract Only (APAC)", "crm-pack")
	projection := mustRuntimeStartupShallowProjectionJSON(t, expected)
	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindRecordType, BusinessKey: JoinComponentBusinessKey("Account", "Contract_Only_APAC")},
	}))
	expectEmptyAppPackStartupShallowSupportedScans(mock, "crm-pack", ComponentKindRecordType)
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows(expected))
	mock.ExpectQuery("SELECT AppliedPayloadHash, ManifestFormatVersion, SourceKind, SourceURI, SourceRevision\\s+FROM _System_InstalledPack").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"AppliedPayloadHash", "ManifestFormatVersion", "SourceKind", "SourceURI", "SourceRevision"}).
			AddRow("hash-123", SupportedManifestFormatVersion, string(PackSourceKindLocalPath), "/tmp/crm-pack", nil))
	expectRecordTypeStartupShallowProjectionQuery(mock, "Account", "Contract_Only_APAC", "Contract Only (APAC)", expected)

	originalResolveInstalledPack := resolveInstalledPackForStartupShallowCompat
	resolveInstalledPackForStartupShallowCompat = func(input InstalledPackResolverInput, opts InstalledPackResolverOptions) (Pack, error) {
		return runtimeStartupShallowDeclaredCompatPack{
			rows: []runtimeStartupShallowDeclaredRow{{Kind: ComponentKindRecordType, BusinessKey: JoinComponentBusinessKey("Account", "Contract_Only_APAC"), Projection: projection}},
		}, nil
	}
	defer func() { resolveInstalledPackForStartupShallowCompat = originalResolveInstalledPack }()

	err = VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack)
	if err == nil || !strings.Contains(err.Error(), "record_type Account/Contract_Only_APAC projection invalid") {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName error = %v, want record_type blank projection fail closed", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameFailsClosedForRemovedRecordTypeOrphan(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	extra := recordTypeStartupShallowProjection("Account", "Consumer", "crm-pack")
	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", `[]`)
	expectEmptyAppPackStartupShallowSupportedScans(mock, "crm-pack", ComponentKindRecordType)
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows(extra))
	mock.ExpectQuery("SELECT AppliedPayloadHash, ManifestFormatVersion, SourceKind, SourceURI, SourceRevision\\s+FROM _System_InstalledPack").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"AppliedPayloadHash", "ManifestFormatVersion", "SourceKind", "SourceURI", "SourceRevision"}).
			AddRow("hash-123", SupportedManifestFormatVersion, string(PackSourceKindLocalPath), "/tmp/crm-pack", nil))

	originalResolveInstalledPack := resolveInstalledPackForStartupShallowCompat
	resolveInstalledPackForStartupShallowCompat = func(input InstalledPackResolverInput, opts InstalledPackResolverOptions) (Pack, error) {
		return runtimeStartupShallowDeclaredCompatPack{}, nil
	}
	defer func() { resolveInstalledPackForStartupShallowCompat = originalResolveInstalledPack }()

	err = VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack)
	if err == nil || !strings.Contains(err.Error(), "record_type Account/Consumer legacy omission drift") {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName error = %v, want removed-family record_type drift", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func expectEmptyAppPackStartupShallowSupportedScansWithFlowActionRows(mock sqlmock.Sqlmock, packName string, flowRows *sqlmock.Rows) {
	expectRuntimeObjectSpecDeclarationQuery(mock, packName, `[]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs(packName).
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs(packName).
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs(packName).
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, packName).
		WillReturnRows(flowRows)
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs(packName).
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, packName).
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs(packName).
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs(packName).
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs(packName).
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, packName).
		WillReturnRows(recordTypeStartupShallowRows())
}

func TestVerifyInstalledPersistedRuntimeShallowByNameRejectsFlowActionRuntimeRegistryDrift(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	projection := mustRuntimeStartupShallowProjectionJSON(t, sourceBackedFlowActionCallHandlerProjection{
		OwnerPack:       "crm-pack",
		ActionType:      "sendemail",
		HandlerRef:      "platform:automation/send-email",
		AtomicPolicy:    "safe",
		PreviewPolicy:   "reject_email_io",
		RequiresContext: "none",
		SendsEmail:      true,
	})
	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindFlowActionCallHandler, BusinessKey: "sendemail", Projection: projection},
	}))
	expectEmptyAppPackStartupShallowSupportedScansWithFlowActionRows(
		mock,
		"crm-pack",
		sqlmock.NewRows([]string{"ActionType"}).AddRow("sendEmail"),
	)
	mock.ExpectQuery("SELECT OwnerPack, ActionType, HandlerRef, AtomicPolicy, PreviewPolicy, RequiresContext, COALESCE\\(SendsEmail, 0\\)\\s+FROM _System_FlowActionCallHandler").
		WithArgs("sendemail").
		WillReturnRows(sqlmock.NewRows([]string{"OwnerPack", "ActionType", "HandlerRef", "AtomicPolicy", "PreviewPolicy", "RequiresContext", "SendsEmail"}).
			AddRow("crm-pack", "sendEmail", "platform:automation/send-email", "safe", "reject_email_io", "none", true))

	err = VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack)
	if err == nil || !strings.Contains(err.Error(), "conflicts with runtime registration") {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName error = %v, want runtime registration drift", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameAcceptsFlowActionDefaultHandlerImplementation(t *testing.T) {
	restore := flowactions.ResetForTest()
	t.Cleanup(restore)
	registerTestFlowActionCallHandlerImplementationsForTest(t)

	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	projection := mustRuntimeStartupShallowProjectionJSON(t, sourceBackedFlowActionCallHandlerProjection{
		OwnerPack:       "jira-like-sample",
		ActionType:      "stampconvertedanchors",
		HandlerRef:      "crm:standard-action/stamp-converted-anchors",
		AtomicPolicy:    "safe",
		PreviewPolicy:   "reject",
		RequiresContext: "standard_action_protected",
	})
	expectRuntimeStartupShallowDeclarationQuery(mock, "jira-like-sample", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindFlowActionCallHandler, BusinessKey: "stampconvertedanchors", Projection: projection},
	}))
	expectEmptyAppPackStartupShallowSupportedScansWithFlowActionRows(
		mock,
		"jira-like-sample",
		sqlmock.NewRows([]string{"ActionType"}).AddRow("stampConvertedAnchors"),
	)
	mock.ExpectQuery("SELECT OwnerPack, ActionType, HandlerRef, AtomicPolicy, PreviewPolicy, RequiresContext, COALESCE\\(SendsEmail, 0\\)\\s+FROM _System_FlowActionCallHandler").
		WithArgs("stampconvertedanchors").
		WillReturnRows(sqlmock.NewRows([]string{"OwnerPack", "ActionType", "HandlerRef", "AtomicPolicy", "PreviewPolicy", "RequiresContext", "SendsEmail"}).
			AddRow("jira-like-sample", "stampConvertedAnchors", "crm:standard-action/stamp-converted-anchors", "safe", "reject", "standard_action_protected", false))

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "jira-like-sample", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameAcceptsMatchingBlankListFieldsProjection(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	projection := mustRuntimeStartupShallowProjectionJSON(t, runtimeStartupShallowListFieldsProjection{
		ObjectAPIName: "Issue",
		Fields:        []string{},
	})
	expectRuntimeStartupShallowDeclarationQuery(mock, "jira-like-sample", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindListFields, BusinessKey: "Issue", Projection: projection},
	}))
	expectRuntimeObjectSpecDeclarationQuery(mock, "jira-like-sample", `[[{"apiName":"Issue"}]]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("jira-like-sample").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT ApiName, ListFields, COALESCE\\(ListFieldsCustomized, 0\\)\\s+FROM _System_Object").
		WithArgs("Issue").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ListFields", "ListFieldsCustomized"}).
			AddRow("Issue", ``, false))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("jira-like-sample").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("jira-like-sample").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "jira-like-sample").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("jira-like-sample").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "jira-like-sample").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("jira-like-sample").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("jira-like-sample").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("jira-like-sample").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "jira-like-sample").
		WillReturnRows(recordTypeStartupShallowRows())
	mock.ExpectQuery("SELECT ListFields, ListFieldsCustomized\\s+FROM _System_Object").
		WithArgs("Issue").
		WillReturnRows(sqlmock.NewRows([]string{"ListFields", "ListFieldsCustomized"}).AddRow(``, false))

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "jira-like-sample", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameFailsClosedForLegacyListFieldsWithoutSourceIdentity(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindListFields, BusinessKey: "Lead"},
	}))
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[[{"apiName":"Lead"}]]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT ApiName, ListFields, COALESCE\\(ListFieldsCustomized, 0\\)\\s+FROM _System_Object").
		WithArgs("Lead").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ListFields", "ListFieldsCustomized"}).
			AddRow("Lead", `["Name","Status"]`, false))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())
	mock.ExpectQuery("SELECT AppliedPayloadHash, ManifestFormatVersion, SourceKind, SourceURI, SourceRevision\\s+FROM _System_InstalledPack").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"AppliedPayloadHash", "ManifestFormatVersion", "SourceKind", "SourceURI", "SourceRevision"}).
			AddRow(nil, nil, nil, nil, nil))

	err = VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack)
	if err == nil || !strings.Contains(err.Error(), "list_fields Lead projection drift: source identity missing required source locator fields") {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName error = %v, want source-less legacy list_fields fail-close", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameAcceptsLegacyListFieldsProjectionFromSourceIdentity(t *testing.T) {
	registrations := testRuntimeStartupShallowRegistrationSet(t)
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindListFields, BusinessKey: "Lead"},
	}))
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[[{"apiName":"Lead"}]]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT ApiName, ListFields, COALESCE\\(ListFieldsCustomized, 0\\)\\s+FROM _System_Object").
		WithArgs("Lead").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ListFields", "ListFieldsCustomized"}).
			AddRow("Lead", `["Name","Status"]`, false))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())
	mock.ExpectQuery("SELECT AppliedPayloadHash, ManifestFormatVersion, SourceKind, SourceURI, SourceRevision\\s+FROM _System_InstalledPack").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"AppliedPayloadHash", "ManifestFormatVersion", "SourceKind", "SourceURI", "SourceRevision"}).
			AddRow("hash-123", SupportedManifestFormatVersion, string(PackSourceKindLocalPath), "/tmp/crm-pack", nil))
	mock.ExpectQuery("SELECT ListFields, ListFieldsCustomized\\s+FROM _System_Object").
		WithArgs("Lead").
		WillReturnRows(sqlmock.NewRows([]string{"ListFields", "ListFieldsCustomized"}).AddRow(`["Name","Status"]`, false))

	originalResolveInstalledPack := resolveInstalledPackForStartupShallowCompat
	resolveInstalledPackForStartupShallowCompat = func(input InstalledPackResolverInput, opts InstalledPackResolverOptions) (Pack, error) {
		if input.AppliedPayloadHash != "hash-123" {
			t.Fatalf("AppliedPayloadHash = %q, want hash-123", input.AppliedPayloadHash)
		}
		if input.SourceKind != string(PackSourceKindLocalPath) {
			t.Fatalf("SourceKind = %q, want %q", input.SourceKind, string(PackSourceKindLocalPath))
		}
		if input.SourceURI != "/tmp/crm-pack" {
			t.Fatalf("SourceURI = %q, want /tmp/crm-pack", input.SourceURI)
		}
		if opts.ComponentKindRegistrationSet == nil || len(opts.ComponentKindRegistrationSet.Registrations()) != 1 {
			t.Fatal("list_fields fallback did not receive the registration snapshot")
		}
		projection := mustRuntimeStartupShallowProjectionJSON(t, runtimeStartupShallowListFieldsProjection{
			ObjectAPIName: "Lead",
			Fields:        []string{"Name", "Status"},
		})
		return runtimeStartupShallowDeclaredCompatPack{
			rows: []runtimeStartupShallowDeclaredRow{{Kind: ComponentKindListFields, BusinessKey: "Lead", Projection: projection}},
		}, nil
	}
	defer func() { resolveInstalledPackForStartupShallowCompat = originalResolveInstalledPack }()

	if err := VerifyInstalledPersistedRuntimeShallowByNameWithComponentKindRegistrationSet(context.Background(), db, "crm-pack", AppPack, registrations); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameIgnoresCustomizedUndeclaredDefaultsOnlyRows(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindValidationRule, BusinessKey: "Lead/RequireName", Projection: mustValidationRuleStartupShallowProjectionJSON(t, "Lead", "RequireName", true, "ISBLANK(Name)", "Name is required")},
		{Kind: ComponentKindInvocableAction, BusinessKey: "ConvertLead"},
		{Kind: ComponentKindUIAction, BusinessKey: "Lead/CreateTask"},
		{Kind: ComponentKindStandardFlow, BusinessKey: "Lead_AutoAssign"},
		{Kind: ComponentKindFieldMapping, BusinessKey: "Lead/Account/convert/Company"},
	}))
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}).
			AddRow("Lead", "RequireName", false).
			AddRow("Lead", "LegacyRetained", true))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}).
			AddRow("ConvertLead", false).
			AddRow("LegacyAction", true))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}).
			AddRow("Lead", "CreateTask"))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}).
			AddRow("Lead_AutoAssign", false).
			AddRow("Lead_RetainedOverride", true))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}).
			AddRow("Lead", "Account", "convert", "Company", "", false).
			AddRow("Lead", "Account", "convert", "LegacyField", "", true))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())
	mock.ExpectQuery("SELECT COALESCE\\(IsDeleted, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack", "ConvertLead").
		WillReturnRows(sqlmock.NewRows([]string{"IsDeleted"}).AddRow(false))
	expectValidationRuleStartupShallowDeclaredRowPredicateActive(mock)
	expectValidationRuleStartupShallowExistenceQuery(mock, "crm-pack", "Lead", "RequireName", "1 = 1")
	expectValidationRuleStartupShallowDeclaredRowPredicateActive(mock)
	expectValidationRuleStartupShallowProjectionQuery(mock, "crm-pack", "Lead", "RequireName", "1 = 1", true, "ISBLANK(Name)", "Name is required", false)

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameIgnoresInactiveRetainedValidationRules(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindValidationRule, BusinessKey: "Lead/RequireName", Projection: mustValidationRuleStartupShallowProjectionJSON(t, "Lead", "RequireName", true, "ISBLANK(Name)", "Name is required")},
	}))
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}).
			AddRow("Lead", "RequireName", false))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())
	expectValidationRuleStartupShallowDeclaredRowPredicateActive(mock)
	expectValidationRuleStartupShallowExistenceQuery(mock, "crm-pack", "Lead", "RequireName", "1 = 1")
	expectValidationRuleStartupShallowDeclaredRowPredicateActive(mock)
	expectValidationRuleStartupShallowProjectionQuery(mock, "crm-pack", "Lead", "RequireName", "1 = 1", true, "ISBLANK(Name)", "Name is required", false)

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameSkipsAutoNumberCounterLiveScopeVerification(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", `[{"kind":"autonumber_counter","businessKey":"Lead/CaseNumber/per_day"}]`)
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameFallsBackToValidationRuleIsDeletedWithoutActive(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindValidationRule, BusinessKey: "Lead/RequireName", Projection: mustValidationRuleStartupShallowProjectionJSON(t, "Lead", "RequireName", true, "ISBLANK(Name)", "Name is required")},
	}))
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(0))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "IsDeleted").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}).
			AddRow("Lead", "RequireName", false))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())
	expectValidationRuleStartupShallowDeclaredRowPredicateIsDeleted(mock)
	expectValidationRuleStartupShallowExistenceQuery(mock, "crm-pack", "Lead", "RequireName", validationRuleStartupShallowLegacyRetainedCustomizedPredicate)
	expectValidationRuleStartupShallowDeclaredRowPredicateIsDeleted(mock)
	expectValidationRuleStartupShallowProjectionQuery(mock, "crm-pack", "Lead", "RequireName", validationRuleStartupShallowLegacyRetainedCustomizedPredicate, true, "ISBLANK(Name)", "Name is required", false)

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameFailsClosedForDeletedValidationRuleCompatibilityRow(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindValidationRule, BusinessKey: "Lead/RequireName", Projection: mustValidationRuleStartupShallowProjectionJSON(t, "Lead", "RequireName", true, "ISBLANK(Name)", "Name is required")},
	}))
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(0))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "IsDeleted").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(0))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "IsDeleted").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT 1\\s+FROM _System_ValidationRule\\s+WHERE COALESCE\\(OwnerPack, ''\\) = \\?\\s+AND ObjectApiName = \\?\\s+AND Name = \\?\\s+AND "+validationRuleStartupShallowLegacyRetainedCustomizedPredicate+"\\s+LIMIT 1").
		WithArgs("crm-pack", "Lead", "RequireName").
		WillReturnRows(sqlmock.NewRows([]string{"1"}))

	err = VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack)
	if err == nil || !strings.Contains(err.Error(), "validation_rule Lead/RequireName is missing") {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName error = %v, want missing deleted compatibility row", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameAcceptsDeletedCustomizedRetainedValidationRuleCompatibilityRow(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindValidationRule, BusinessKey: "Lead/RequireName", Projection: mustValidationRuleStartupShallowProjectionJSON(t, "Lead", "RequireName", true, "ISBLANK(Name)", "Name is required")},
	}))
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(0))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "IsDeleted").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}).
			AddRow("Lead", "RequireName", true))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())
	expectValidationRuleStartupShallowDeclaredRowPredicateIsDeleted(mock)
	expectValidationRuleStartupShallowExistenceQuery(mock, "crm-pack", "Lead", "RequireName", validationRuleStartupShallowLegacyRetainedCustomizedPredicate)
	expectValidationRuleStartupShallowDeclaredRowPredicateIsDeleted(mock)
	expectValidationRuleStartupShallowProjectionQuery(mock, "crm-pack", "Lead", "RequireName", validationRuleStartupShallowLegacyRetainedCustomizedPredicate, false, "FALSE", "drifted but customized", true)

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameAcceptsDeclaredInactiveValidationRuleMissingFromLiveScan(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindValidationRule, BusinessKey: "Lead/RequireName", Projection: mustValidationRuleStartupShallowProjectionJSON(t, "Lead", "RequireName", false, "ISBLANK(Name)", "Name is required")},
	}))
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule\\s+WHERE COALESCE\\(OwnerPack, ''\\) = \\?\\s+AND \\(COALESCE\\(Active, 0\\) = 1 OR COALESCE\\(IsCustomized, 0\\) = 1\\)").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())
	expectValidationRuleStartupShallowDeclaredRowPredicateActive(mock)
	expectValidationRuleStartupShallowExistenceQuery(mock, "crm-pack", "Lead", "RequireName", "1 = 1")
	expectValidationRuleStartupShallowDeclaredRowPredicateActive(mock)
	expectValidationRuleStartupShallowProjectionQuery(mock, "crm-pack", "Lead", "RequireName", "1 = 1", false, "ISBLANK(Name)", "Name is required", false)

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestSourceLessValidationRuleLiveRowsPredicateIncludesCustomizedRetainedRowsWithActive(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))

	got, err := sourceLessValidationRuleLiveRowsPredicate(context.Background(), db)
	if err != nil {
		t.Fatalf("sourceLessValidationRuleLiveRowsPredicate: %v", err)
	}
	if got != "(COALESCE(Active, 0) = 1 OR COALESCE(IsCustomized, 0) = 1)" {
		t.Fatalf("predicate = %q, want active-or-customized retained predicate", got)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestSourceLessValidationRuleLiveRowsPredicateIncludesCustomizedRetainedRowsWithIsDeletedFallback(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(0))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "IsDeleted").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))

	got, err := sourceLessValidationRuleLiveRowsPredicate(context.Background(), db)
	if err != nil {
		t.Fatalf("sourceLessValidationRuleLiveRowsPredicate: %v", err)
	}
	if got != "(COALESCE(IsDeleted, 0) = 0 OR COALESCE(IsCustomized, 0) = 1)" {
		t.Fatalf("predicate = %q, want undeleted-or-customized retained predicate", got)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameAcceptsLegacyProjectionlessValidationRuleFromSourceIdentity(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", `[{"kind":"validation_rule","businessKey":"Lead/RequireName"}]`)
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}).
			AddRow("Lead", "RequireName", false))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())
	expectValidationRuleStartupShallowDeclaredRowPredicateActive(mock)
	expectValidationRuleStartupShallowExistenceQuery(mock, "crm-pack", "Lead", "RequireName", "1 = 1")
	mock.ExpectQuery("SELECT AppliedPayloadHash, ManifestFormatVersion, SourceKind, SourceURI, SourceRevision\\s+FROM _System_InstalledPack").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"AppliedPayloadHash", "ManifestFormatVersion", "SourceKind", "SourceURI", "SourceRevision"}).
			AddRow("hash-123", SupportedManifestFormatVersion, string(PackSourceKindLocalPath), "/tmp/crm-pack", nil))
	expectValidationRuleStartupShallowDeclaredRowPredicateActive(mock)
	expectValidationRuleStartupShallowProjectionQuery(mock, "crm-pack", "Lead", "RequireName", "1 = 1", true, "ISBLANK(Name)", "Name is required", false)

	originalResolveInstalledPack := resolveInstalledPackForStartupShallowCompat
	resolveInstalledPackForStartupShallowCompat = func(input InstalledPackResolverInput, opts InstalledPackResolverOptions) (Pack, error) {
		if input.AppliedPayloadHash != "hash-123" {
			t.Fatalf("AppliedPayloadHash = %q, want hash-123", input.AppliedPayloadHash)
		}
		if input.SourceKind != string(PackSourceKindLocalPath) {
			t.Fatalf("SourceKind = %q, want %q", input.SourceKind, string(PackSourceKindLocalPath))
		}
		if input.SourceURI != "/tmp/crm-pack" {
			t.Fatalf("SourceURI = %q, want /tmp/crm-pack", input.SourceURI)
		}
		return runtimeStartupShallowDeclaredCompatPack{
			rows: []runtimeStartupShallowDeclaredRow{{
				Kind:        ComponentKindValidationRule,
				BusinessKey: JoinComponentBusinessKey("Lead", "RequireName"),
				Projection:  mustValidationRuleStartupShallowProjectionJSON(t, "Lead", "RequireName", true, "ISBLANK(Name)", "Name is required"),
			}},
		}, nil
	}
	defer func() { resolveInstalledPackForStartupShallowCompat = originalResolveInstalledPack }()

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameAcceptsPermissionProjectionWithWhitespacePaddedAPIName(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	projection := mustRuntimeStartupShallowProjectionJSON(t, runtimeStartupShallowPermissionProjection{
		APIName:     " ViewSetup ",
		Label:       "View Setup",
		Category:    "Administrative",
		Description: "Allows viewing setup pages",
		Requires:    "RunReports",
		OwnerPack:   "crm-pack",
		IsSystem:    true,
		IsActive:    true,
	})
	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindPermission, BusinessKey: "ViewSetup", Projection: projection},
	}))
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}).AddRow(" ViewSetup "))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())
	mock.ExpectQuery("SELECT ApiName, Label, Category, COALESCE\\(Description, ''\\), COALESCE\\(RequiresPermission, ''\\), COALESCE\\(OwnerPack, ''\\), IsSystem, IsActive\\s+FROM _System_Permission").
		WithArgs(" ViewSetup ").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "Label", "Category", "Description", "RequiresPermission", "OwnerPack", "IsSystem", "IsActive"}).
			AddRow(" ViewSetup ", "View Setup", "Administrative", "Allows viewing setup pages", "RunReports", "crm-pack", 1, 1))

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

type runtimeStartupShallowDeclaredCompatPack struct {
	rows []runtimeStartupShallowDeclaredRow
}

func (runtimeStartupShallowDeclaredCompatPack) Name() string { return "crm-pack" }

func (runtimeStartupShallowDeclaredCompatPack) Category() Category { return AppPack }

func (runtimeStartupShallowDeclaredCompatPack) Apply(context.Context, ApplyDeps) error { return nil }

func (runtimeStartupShallowDeclaredCompatPack) Verify(context.Context, VerifyDeps) error { return nil }

func (p runtimeStartupShallowDeclaredCompatPack) RuntimeStartupShallowDeclaredRows() []runtimeStartupShallowDeclaredRow {
	return append([]runtimeStartupShallowDeclaredRow(nil), p.rows...)
}

func TestVerifyInstalledPersistedRuntimeShallowByNameFailsClosedForCorruptPermissionProjection(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindPermission, BusinessKey: "ViewSetup", Projection: "{"},
	}))
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}).AddRow("ViewSetup"))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())

	err = VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack)
	if err == nil || !strings.Contains(err.Error(), "permission ViewSetup projection invalid") {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName error = %v, want invalid permission projection drift", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameFailsClosedForRemovedKindFamilyOrphans(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	projection := mustRuntimeStartupShallowProjectionJSON(t, runtimeStartupShallowPermissionProjection{
		APIName:   "ViewSetup",
		Label:     "View Setup",
		Category:  "Administrative",
		OwnerPack: "crm-pack",
		IsSystem:  true,
		IsActive:  true,
	})
	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindPermission, BusinessKey: "ViewSetup", Projection: projection},
	}))
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}).AddRow("ViewSetup"))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}).AddRow("Lead", "LegacyRetained", false))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())
	mock.ExpectQuery("SELECT ApiName, Label, Category, COALESCE\\(Description, ''\\), COALESCE\\(RequiresPermission, ''\\), COALESCE\\(OwnerPack, ''\\), IsSystem, IsActive\\s+FROM _System_Permission").
		WithArgs("ViewSetup").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "Label", "Category", "Description", "RequiresPermission", "OwnerPack", "IsSystem", "IsActive"}).
			AddRow("ViewSetup", "View Setup", "Administrative", "", "", "crm-pack", 1, 1))

	err = VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack)
	if err == nil || !strings.Contains(err.Error(), "validation_rule Lead/LegacyRetained is undeclared") {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName error = %v, want undeclared removed-family validation_rule drift", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameIgnoresUndeclaredListFieldsOnOwnedObjects(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", `[]`)
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[[{"apiName":"Lead"}]]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT ApiName, COALESCE\\(ListFieldsCustomized, 0\\)\\s+FROM _System_Object").
		WithArgs("Lead").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ListFieldsCustomized"}))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNamePreservesConnectorFieldMappingDirection(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindFieldMapping, BusinessKey: "Contact/Person/syncContact/email/bidirectional"},
		{Kind: ComponentKindFieldMapping, BusinessKey: "Contact/Person/syncContact/email/inbound"},
	}))
	expectEmptyAppPackStartupShallowSupportedScans(mock, "crm-pack", ComponentKindFieldMapping, ComponentKindAutoNumberFormat, ComponentKindRecordType)
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}).
			AddRow("Contact", "Person", "syncContact", "email", "bidirectional", false).
			AddRow("Contact", "Person", "syncContact", "email", "inbound", false))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNamePreservesLegacyFieldMappingKey(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindFieldMapping, BusinessKey: "Lead/Account/convert/Company"},
	}))
	expectEmptyAppPackStartupShallowSupportedScans(mock, "crm-pack", ComponentKindFieldMapping, ComponentKindAutoNumberFormat, ComponentKindRecordType)
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}).
			AddRow("Lead", "Account", "convert", "Company", "legacy", false))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestLoadRuntimeStartupShallowLiveProjectionComparesLockedObjectSpecListFieldsCustomized(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	declaredProjection := mustRuntimeStartupShallowProjectionJSON(t, runtimeStartupShallowListFieldsProjection{
		ObjectAPIName: "Issue",
		Fields:        []string{"Subject"},
	})
	mock.ExpectQuery("SELECT ListFields, ListFieldsCustomized\\s+FROM _System_Object").
		WithArgs("Issue").
		WillReturnRows(sqlmock.NewRows([]string{"ListFields", "ListFieldsCustomized"}).AddRow(`["Admin"]`, true))

	cache := &runtimeStartupShallowSourceBackedPackCache{
		loaded: true,
		pack: &SourceBackedPack{components: []PackComponent{
			&sourceBackedObjectSpecComponent{
				manifestComponent: ManifestComponent{Kind: ComponentKindObjectSpec, BusinessKey: "objects", Manageability: ManageabilityLocked},
				specs: []ObjectSpec{{
					APIName:    "Issue",
					ListFields: []string{"Subject"},
				}},
			},
		}},
	}

	got, err := loadRuntimeStartupShallowLiveProjection(context.Background(), db, "crm-pack", AppPack, runtimeStartupShallowDeclaredRow{
		Kind:        ComponentKindListFields,
		BusinessKey: "Issue",
		Projection:  declaredProjection,
	}, declaredProjection, cache, nil)
	if err != nil {
		t.Fatalf("loadRuntimeStartupShallowLiveProjection: %v", err)
	}
	if got == declaredProjection {
		t.Fatalf("live projection = declared projection, want locked customized drift to compare live")
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestLoadRuntimeStartupShallowLiveProjectionReadsExactConnectorCalloutProfileGeneration(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	projection := ConnectorCalloutProfileFinalizationProjection{
		OwnerPack: "connector-a", ProfileName: "default",
		CredentialRef: "credential-a", EndpointClass: "crm.write",
		MaxAttempts: 3, BaseDelayNanos: 1_000_000, Multiplier: 2, MaxDelayNanos: 10_000_000,
		RetryableStatusCodes: []int{429, 503},
	}
	declaredProjection, err := marshalConnectorCalloutProfileFinalizationProjection(projection)
	if err != nil {
		t.Fatal(err)
	}
	mock.ExpectQuery("SELECT PackInstallId\\s+FROM _System_InstalledPack").
		WithArgs("connector-a").
		WillReturnRows(sqlmock.NewRows([]string{"PackInstallId"}).AddRow("install-a"))
	mock.ExpectQuery("SELECT InstalledPackId, OwnerPack, ProfileName, CredentialRef, EndpointClass").
		WithArgs("connector-a", "install-a", "default").
		WillReturnRows(sqlmock.NewRows([]string{
			"InstalledPackId", "OwnerPack", "ProfileName", "CredentialRef", "EndpointClass",
			"RetryPolicy", "PageSpec", "BatchSpec", "ObjectPathMap", "Description",
		}).AddRow(
			"install-a", "connector-a", "default", "credential-a", "crm.write",
			`{"maxAttempts":3,"baseDelay":1000000,"multiplier":2,"maxDelay":10000000,"retryableStatusCodes":[429,503]}`,
			`{}`, `{}`, `{}`, "provider detail excluded",
		))

	got, err := loadRuntimeStartupShallowLiveProjection(
		context.Background(),
		db,
		"connector-a",
		ConnectorPack,
		runtimeStartupShallowDeclaredRow{
			Kind: ComponentKindConnectorCalloutProfile, BusinessKey: "default", Projection: declaredProjection,
		},
		declaredProjection,
		&runtimeStartupShallowSourceBackedPackCache{},
		nil,
	)
	if err != nil {
		t.Fatalf("loadRuntimeStartupShallowLiveProjection: %v", err)
	}
	if got != declaredProjection {
		t.Fatalf("live finalization projection = %s, want %s", got, declaredProjection)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestLoadRuntimeStartupShallowLiveProjectionAllowsDefaultsOnlyObjectSpecListFieldsCustomized(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	declaredProjection := mustRuntimeStartupShallowProjectionJSON(t, runtimeStartupShallowListFieldsProjection{
		ObjectAPIName: "Issue",
		Fields:        []string{"Subject"},
	})
	mock.ExpectQuery("SELECT ListFields, ListFieldsCustomized\\s+FROM _System_Object").
		WithArgs("Issue").
		WillReturnRows(sqlmock.NewRows([]string{"ListFields", "ListFieldsCustomized"}).AddRow(`["Admin"]`, true))

	cache := &runtimeStartupShallowSourceBackedPackCache{
		loaded: true,
		pack: &SourceBackedPack{components: []PackComponent{
			&sourceBackedObjectSpecComponent{
				manifestComponent: ManifestComponent{Kind: ComponentKindObjectSpec, BusinessKey: "objects", Manageability: ManageabilityDefaultsOnly},
				specs: []ObjectSpec{{
					APIName:    "Issue",
					ListFields: []string{"Subject"},
				}},
			},
		}},
	}

	got, err := loadRuntimeStartupShallowLiveProjection(context.Background(), db, "crm-pack", AppPack, runtimeStartupShallowDeclaredRow{
		Kind:        ComponentKindListFields,
		BusinessKey: "Issue",
		Projection:  declaredProjection,
	}, declaredProjection, cache, nil)
	if err != nil {
		t.Fatalf("loadRuntimeStartupShallowLiveProjection: %v", err)
	}
	if got != declaredProjection {
		t.Fatalf("live projection = %s, want declared projection for defaults_only customized override", got)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestSourceBackedPackListFieldsLiveOverrideAllowedForDefaultsOnlyObjectSpecOmission(t *testing.T) {
	allowed, known := sourceBackedPackListFieldsLiveOverrideAllowed(&SourceBackedPack{components: []PackComponent{
		&sourceBackedObjectSpecComponent{
			manifestComponent: ManifestComponent{Kind: ComponentKindObjectSpec, BusinessKey: "objects", Manageability: ManageabilityDefaultsOnly},
			specs:             []ObjectSpec{{APIName: "Issue"}},
		},
	}}, "Issue")
	if !known {
		t.Fatal("sourceBackedPackListFieldsLiveOverrideAllowed known = false, want true for object_spec-owned object")
	}
	if !allowed {
		t.Fatal("sourceBackedPackListFieldsLiveOverrideAllowed allowed = false, want true for defaults_only object_spec omission")
	}
}

func TestSourceBackedPackListFieldsLiveOverrideAllowedLockedObjectSpecWinsOverStandalone(t *testing.T) {
	standalone, err := newSourceBackedListFieldsComponent("crm-pack", ManifestComponent{
		Kind:          ComponentKindListFields,
		BusinessKey:   "issue-list-fields",
		Manageability: ManageabilityDefaultsOnly,
	}, []byte(`{"Issue":["Status"]}`))
	if err != nil {
		t.Fatalf("newSourceBackedListFieldsComponent: %v", err)
	}
	allowed, known := sourceBackedPackListFieldsLiveOverrideAllowed(&SourceBackedPack{components: []PackComponent{
		&sourceBackedObjectSpecComponent{
			manifestComponent: ManifestComponent{Kind: ComponentKindObjectSpec, BusinessKey: "objects", Manageability: ManageabilityLocked},
			specs: []ObjectSpec{{
				APIName:    "Issue",
				ListFields: []string{"Subject"},
			}},
		},
		standalone,
	}}, "Issue")
	if !known {
		t.Fatal("sourceBackedPackListFieldsLiveOverrideAllowed known = false, want true for locked object_spec-owned object")
	}
	if allowed {
		t.Fatal("sourceBackedPackListFieldsLiveOverrideAllowed allowed = true, want false for locked object_spec listFields")
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameFailsClosedForRemovedListFieldsOrphan(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", `[]`)
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[[{"apiName":"Lead"}]]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT ApiName, COALESCE\\(ListFieldsCustomized, 0\\)\\s+FROM _System_Object").
		WithArgs("Lead").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ListFieldsCustomized"}).
			AddRow("Lead", true))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())
	mock.ExpectQuery("SELECT AppliedPayloadHash, ManifestFormatVersion, SourceKind, SourceURI, SourceRevision\\s+FROM _System_InstalledPack").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"AppliedPayloadHash", "ManifestFormatVersion", "SourceKind", "SourceURI", "SourceRevision"}).
			AddRow("hash-123", SupportedManifestFormatVersion, string(PackSourceKindLocalPath), "/tmp/crm-pack", nil))

	originalResolveInstalledPack := resolveInstalledPackForStartupShallowCompat
	resolveInstalledPackForStartupShallowCompat = func(input InstalledPackResolverInput, opts InstalledPackResolverOptions) (Pack, error) {
		if input.AppliedPayloadHash != "hash-123" {
			t.Fatalf("AppliedPayloadHash = %q, want hash-123", input.AppliedPayloadHash)
		}
		return &SourceBackedPack{components: []PackComponent{
			&sourceBackedObjectSpecComponent{
				manifestComponent: ManifestComponent{Kind: ComponentKindObjectSpec, BusinessKey: "objects", Manageability: ManageabilityLocked},
				specs:             []ObjectSpec{{APIName: "Lead"}},
			},
		}}, nil
	}
	defer func() { resolveInstalledPackForStartupShallowCompat = originalResolveInstalledPack }()

	err = VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack)
	if err == nil || !strings.Contains(err.Error(), "list_fields Lead is undeclared") {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName error = %v, want undeclared list_fields drift", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameListFieldsScopesLiveCompareToDeclaredRows(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	projection := mustRuntimeStartupShallowProjectionJSON(t, runtimeStartupShallowListFieldsProjection{
		ObjectAPIName: "Issue",
		Fields:        []string{"Summary", "Status"},
	})
	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindListFields, BusinessKey: "Issue", Projection: projection},
	}))
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[[{"apiName":"Issue"},{"apiName":"Lead"}]]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT ApiName, ListFields, COALESCE\\(ListFieldsCustomized, 0\\)\\s+FROM _System_Object").
		WithArgs("Issue").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ListFields", "ListFieldsCustomized"}).
			AddRow("Issue", `["Summary","Status"]`, false))
	mock.ExpectQuery("SELECT ApiName, COALESCE\\(ListFieldsCustomized, 0\\)\\s+FROM _System_Object").
		WithArgs("Lead").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ListFieldsCustomized"}))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())
	mock.ExpectQuery("SELECT ListFields, ListFieldsCustomized\\s+FROM _System_Object").
		WithArgs("Issue").
		WillReturnRows(sqlmock.NewRows([]string{"ListFields", "ListFieldsCustomized"}).AddRow(`["Summary","Status"]`, false))

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameIgnoresRetainedApprovalProcessDeclaration(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	projection := `{"objectApiName":"Lead","developerName":"LeadApproval","ownerPack":"crm-pack"}`
	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindApprovalProcess, BusinessKey: "Lead/LeadApproval", Projection: projection},
	}))
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameIgnoresRetainedInactiveUndeclaredInvocableAction(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	projection := mustRuntimeStartupShallowProjectionJSON(t, runtimeStartupShallowPermissionProjection{
		APIName:     "ViewSetup",
		Label:       "View Setup",
		Category:    "Administrative",
		Description: "Allows viewing setup pages",
		OwnerPack:   "crm-pack",
		IsSystem:    true,
		IsActive:    true,
	})
	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", mustRuntimeStartupShallowDeclarationJSON(t, []runtimeStartupShallowDeclaredRow{
		{Kind: ComponentKindPermission, BusinessKey: "ViewSetup", Projection: projection},
	}))
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}).AddRow("ViewSetup"))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())
	mock.ExpectQuery("SELECT ApiName, Label, Category, COALESCE\\(Description, ''\\), COALESCE\\(RequiresPermission, ''\\), COALESCE\\(OwnerPack, ''\\), IsSystem, IsActive\\s+FROM _System_Permission").
		WithArgs("ViewSetup").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "Label", "Category", "Description", "RequiresPermission", "OwnerPack", "IsSystem", "IsActive"}).
			AddRow("ViewSetup", "View Setup", "Administrative", "Allows viewing setup pages", "", "crm-pack", 1, 1))

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}

func TestVerifyInstalledPersistedRuntimeShallowByNameAcceptsCustomizedUndeletedDeclaredStandardFlowWithoutLiveFlowRow(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("sqlmock: %v", err)
	}
	defer db.Close()

	expectRuntimeStartupShallowDeclarationQuery(mock, "crm-pack", `[{"kind":"standard_flow","businessKey":"Lead_AutoAssign"}]`)
	expectRuntimeObjectSpecDeclarationQuery(mock, "crm-pack", `[]`)
	mock.ExpectQuery("SELECT ApiName\\s+FROM _System_Permission").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName"}))
	mock.ExpectQuery("SELECT COUNT\\(\\*\\)\\s+FROM information_schema.columns").
		WithArgs("_System_ValidationRule", "Active").
		WillReturnRows(sqlmock.NewRows([]string{"COUNT(*)"}).AddRow(1))
	mock.ExpectQuery("SELECT ObjectApiName, Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ValidationRule").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name", "IsCustomized"}))
	mock.ExpectQuery("SELECT Name, COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_StandardAction").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"Name", "IsCustomized"}))
	expectFlowActionCallHandlerStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ActionType"}))
	mock.ExpectQuery("SELECT FullName\\s+FROM _System_ReportType").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"FullName"}))
	expectUIActionStartupShallowQuery(mock, "crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ObjectApiName", "Name"}))
	mock.ExpectQuery("SELECT DISTINCT fd.DeveloperName, COALESCE\\(fd.IsCustomized, 0\\)\\s+FROM FlowDefinition fd").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"DeveloperName", "IsCustomized"}))
	mock.ExpectQuery("SELECT SourceObject, TargetObject, ActionType, SourceField, COALESCE\\(Direction, ''\\), COALESCE\\(IsCustomized, 0\\)\\s+FROM _System_ObjectFieldMapping").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"SourceObject", "TargetObject", "ActionType", "SourceField", "Direction", "IsCustomized"}))
	mock.ExpectQuery("SELECT o.ApiName, f.ApiName\\s+FROM _System_Field f").
		WithArgs("crm-pack").
		WillReturnRows(sqlmock.NewRows([]string{"ApiName", "ApiName"}))
	expectRecordTypeStartupShallowScan(mock, "crm-pack").
		WillReturnRows(recordTypeStartupShallowRows())
	mock.ExpectQuery("SELECT COALESCE\\(IsCustomized, 0\\)\\s+FROM FlowDefinition").
		WithArgs("crm-pack", "Lead_AutoAssign").
		WillReturnRows(sqlmock.NewRows([]string{"IsCustomized"}).AddRow(true))

	if err := VerifyInstalledPersistedRuntimeShallowByName(context.Background(), db, "crm-pack", AppPack); err != nil {
		t.Fatalf("VerifyInstalledPersistedRuntimeShallowByName: %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("sql expectations: %v", err)
	}
}
