supa-seed
Version:
A constraint-aware, framework-agnostic database seeding framework with deep PostgreSQL business logic discovery and MakerKit integration support
586 lines • 27.1 kB
JavaScript
;
/**
* Override Validation System for Epic 2: Smart Platform Detection Engine
* Validates manual platform and domain overrides against auto-detection results
* Part of Task 2.4.2: Create override validation utilities (FR-2.5)
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.DEFAULT_OVERRIDE_VALIDATION_OPTIONS = exports.OverrideValidationUtils = exports.OverrideValidator = void 0;
const logger_1 = require("../../core/utils/logger");
/**
* Main Override Validation Engine
*/
class OverrideValidator {
/**
* Validate manual overrides against detection results
*/
async validateOverrides(config, detectionResults, options = {}) {
const startTime = Date.now();
const fullOptions = this.mergeWithDefaults(options);
logger_1.Logger.debug('🔍 Validating manual overrides against detection results...');
try {
// Validate platform architecture override
const platformValidation = await this.validatePlatformArchitectureOverride(config, detectionResults, fullOptions);
// Validate content domain override
const domainValidation = await this.validateContentDomainOverride(config, detectionResults, fullOptions);
// Calculate overall validation result
const overallValid = platformValidation.validation.valid && domainValidation.validation.valid;
const totalConflicts = this.countConflicts(platformValidation, domainValidation);
const highSeverityConflicts = this.countHighSeverityConflicts(platformValidation, domainValidation);
// Generate recommendations based on validation results
const recommendations = this.generateValidationRecommendations(platformValidation, domainValidation, fullOptions);
// Collect all warnings and errors
const allWarnings = [
...platformValidation.validation.warnings,
...domainValidation.validation.warnings
];
const allErrors = [];
if (!platformValidation.validation.valid) {
allErrors.push(`Platform architecture override validation failed`);
}
if (!domainValidation.validation.valid) {
allErrors.push(`Content domain override validation failed`);
}
const validationTime = Date.now() - startTime;
const overallConfidence = (platformValidation.validation.confidence + domainValidation.validation.confidence) / 2;
const result = {
valid: overallValid,
confidence: overallConfidence,
confidenceLevel: this.getConfidenceLevel(overallConfidence),
platformArchitecture: platformValidation,
contentDomain: domainValidation,
validation: {
totalConflicts,
highSeverityConflicts,
validationTime,
validationMethod: 'comprehensive',
recommendations,
warnings: allWarnings,
errors: allErrors
}
};
logger_1.Logger.debug(`Override validation completed in ${validationTime}ms with ${overallConfidence.toFixed(2)} confidence`);
return result;
}
catch (error) {
logger_1.Logger.error('Override validation failed:', error);
return this.createFailureResult(error, Date.now() - startTime);
}
}
/**
* Validate platform architecture override
*/
async validatePlatformArchitectureOverride(config, detectionResults, options) {
const override = config.detection?.platformArchitecture?.override;
const detectedValue = detectionResults.architecture.architectureType;
const detectionConfidence = detectionResults.architecture.confidence;
if (!override) {
// No override specified - validation passes
return {
hasOverride: false,
detectedValue,
conflictSeverity: 'none',
recommendedAction: 'proceed',
validation: {
valid: true,
confidence: 1.0,
reasoning: ['No platform architecture override specified - using auto-detection'],
warnings: []
}
};
}
logger_1.Logger.debug(`Validating platform architecture override: ${override} vs detected: ${detectedValue}`);
const reasoning = [];
const warnings = [];
let conflictSeverity = 'none';
let recommendedAction = 'proceed';
let validationConfidence = 1.0;
// Check for direct mismatch
if (override !== detectedValue) {
const confidenceGap = detectionConfidence - (config.detection?.platformArchitecture?.confidence || 0.5);
if (detectionConfidence > 0.8 && confidenceGap > 0.3) {
conflictSeverity = 'high';
recommendedAction = options.strictMode ? 'reject' : 'review';
validationConfidence = 0.3;
warnings.push(`High-confidence detection (${(detectionConfidence * 100).toFixed(1)}%) conflicts with override`);
reasoning.push(`Override '${override}' conflicts with high-confidence detection '${detectedValue}'`);
}
else if (detectionConfidence > 0.6) {
conflictSeverity = 'medium';
recommendedAction = 'warn';
validationConfidence = 0.6;
warnings.push(`Moderate-confidence detection conflicts with override`);
reasoning.push(`Override '${override}' conflicts with detected '${detectedValue}' (${(detectionConfidence * 100).toFixed(1)}% confidence)`);
}
else {
conflictSeverity = 'low';
recommendedAction = 'proceed';
validationConfidence = 0.8;
reasoning.push(`Override '${override}' accepted - low detection confidence allows override`);
}
}
else {
// Override matches detection
reasoning.push(`Override '${override}' matches detection result - validation passed`);
validationConfidence = Math.min(1.0, detectionConfidence + 0.2); // Boost confidence when override matches
}
// Check for logical consistency with detected patterns
if (this.isArchitectureLogicallyConsistent(override, detectionResults)) {
reasoning.push(`Override is logically consistent with detected schema patterns`);
}
else {
warnings.push(`Override may not be fully consistent with detected schema patterns`);
validationConfidence *= 0.9;
}
const valid = recommendedAction !== 'reject' && (conflictSeverity !== 'high' || !options.strictMode);
return {
hasOverride: true,
overrideValue: override,
detectedValue,
conflictSeverity,
recommendedAction,
validation: {
valid,
confidence: validationConfidence,
reasoning,
warnings
}
};
}
/**
* Validate content domain override
*/
async validateContentDomainOverride(config, detectionResults, options) {
const override = config.detection?.contentDomain?.override;
const detectedValue = detectionResults.domain.primaryDomain;
const detectionConfidence = detectionResults.domain.confidence;
if (!override) {
// No override specified - validation passes
return {
hasOverride: false,
detectedValue,
conflictSeverity: 'none',
recommendedAction: 'proceed',
validation: {
valid: true,
confidence: 1.0,
reasoning: ['No content domain override specified - using auto-detection'],
warnings: []
}
};
}
logger_1.Logger.debug(`Validating content domain override: ${override} vs detected: ${detectedValue}`);
const reasoning = [];
const warnings = [];
let conflictSeverity = 'none';
let recommendedAction = 'proceed';
let validationConfidence = 1.0;
// Check for direct mismatch
if (override !== detectedValue) {
const confidenceGap = detectionConfidence - (config.detection?.contentDomain?.confidence || 0.5);
if (detectionConfidence > 0.8 && confidenceGap > 0.3) {
conflictSeverity = 'high';
recommendedAction = options.strictMode ? 'reject' : 'review';
validationConfidence = 0.3;
warnings.push(`High-confidence detection (${(detectionConfidence * 100).toFixed(1)}%) conflicts with override`);
reasoning.push(`Override '${override}' conflicts with high-confidence detection '${detectedValue}'`);
}
else if (detectionConfidence > 0.6) {
conflictSeverity = 'medium';
recommendedAction = 'warn';
validationConfidence = 0.6;
warnings.push(`Moderate-confidence detection conflicts with override`);
reasoning.push(`Override '${override}' conflicts with detected '${detectedValue}' (${(detectionConfidence * 100).toFixed(1)}% confidence)`);
}
else {
conflictSeverity = 'low';
recommendedAction = 'proceed';
validationConfidence = 0.8;
reasoning.push(`Override '${override}' accepted - low detection confidence allows override`);
}
}
else {
// Override matches detection
reasoning.push(`Override '${override}' matches detection result - validation passed`);
validationConfidence = Math.min(1.0, detectionConfidence + 0.2); // Boost confidence when override matches
}
// Validate domain-specific configurations if enabled
if (options.validateDomainSpecific && config.detection?.contentDomain?.domainSpecific) {
const domainSpecificValidation = this.validateDomainSpecificConfigurations(override, config.detection.contentDomain.domainSpecific, detectionResults);
reasoning.push(...domainSpecificValidation.reasoning);
warnings.push(...domainSpecificValidation.warnings);
validationConfidence *= domainSpecificValidation.confidence;
}
// Check for logical consistency with detected patterns
if (this.isDomainLogicallyConsistent(override, detectionResults)) {
reasoning.push(`Override is logically consistent with detected schema patterns`);
}
else {
warnings.push(`Override may not be fully consistent with detected schema patterns`);
validationConfidence *= 0.9;
}
const valid = recommendedAction !== 'reject' && (conflictSeverity !== 'high' || !options.strictMode);
return {
hasOverride: true,
overrideValue: override,
detectedValue,
conflictSeverity,
recommendedAction,
validation: {
valid,
confidence: validationConfidence,
reasoning,
warnings
}
};
}
/**
* Validate domain-specific configurations
*/
validateDomainSpecificConfigurations(domain, domainSpecific, detectionResults) {
const reasoning = [];
const warnings = [];
let confidence = 1.0;
if (!domainSpecific) {
return { reasoning, warnings, confidence };
}
const domainConfig = domainSpecific[domain];
if (!domainConfig) {
return { reasoning, warnings, confidence };
}
switch (domain) {
case 'outdoor': {
const outdoorConfig = domainConfig;
if (outdoorConfig?.gearCategories && outdoorConfig.gearCategories.length > 0) {
reasoning.push(`Outdoor domain configured with ${outdoorConfig.gearCategories.length} gear categories`);
// Check if categories are realistic for outdoor domain
const validOutdoorCategories = ['camping', 'hiking', 'climbing', 'backpacking', 'skiing', 'kayaking'];
const invalidCategories = outdoorConfig.gearCategories.filter((cat) => !validOutdoorCategories.includes(cat.toLowerCase()));
if (invalidCategories.length > 0) {
warnings.push(`Some gear categories may not be typical for outdoor domain: ${invalidCategories.join(', ')}`);
confidence *= 0.9;
}
}
if (outdoorConfig?.priceRange) {
const { min, max } = outdoorConfig.priceRange;
if (min < 0 || max < min) {
warnings.push(`Invalid price range specified: ${min}-${max}`);
confidence *= 0.8;
}
else if (max > 10000) {
warnings.push(`Price range maximum (${max}) seems high for typical outdoor gear`);
confidence *= 0.95;
}
reasoning.push(`Price range configured: $${min}-$${max}`);
}
break;
}
case 'saas': {
const saasConfig = domainConfig;
if (saasConfig?.workspaceType) {
reasoning.push(`SaaS domain configured for ${saasConfig.workspaceType} workspace`);
// Validate workspace type consistency with platform architecture
const detectedArchitecture = detectionResults.architecture.architectureType;
if (saasConfig.workspaceType === 'team-collaboration' && detectedArchitecture === 'individual') {
warnings.push(`Team collaboration workspace type may not match individual platform architecture`);
confidence *= 0.8;
}
}
break;
}
case 'ecommerce': {
const ecommerceConfig = domainConfig;
if (ecommerceConfig?.storeType) {
reasoning.push(`E-commerce domain configured as ${ecommerceConfig.storeType} store`);
}
if (ecommerceConfig?.productCategories && ecommerceConfig.productCategories.length === 0) {
warnings.push(`E-commerce domain specified but no product categories configured`);
confidence *= 0.9;
}
break;
}
case 'social': {
const socialConfig = domainConfig;
if (socialConfig?.platformType) {
reasoning.push(`Social domain configured as ${socialConfig.platformType} platform`);
}
if (socialConfig?.contentTypes && socialConfig.contentTypes.length === 0) {
warnings.push(`Social domain specified but no content types configured`);
confidence *= 0.9;
}
break;
}
}
return { reasoning, warnings, confidence };
}
/**
* Check if architecture override is logically consistent with detected patterns
*/
isArchitectureLogicallyConsistent(override, detectionResults) {
// Check for obvious inconsistencies based on schema patterns
// Individual platforms typically have simpler schemas
if (override === 'individual') {
// Look for team-specific indicators that would contradict individual architecture
const teamIndicators = detectionResults.integration.recommendations.filter(rec => rec.toLowerCase().includes('team') || rec.toLowerCase().includes('collaboration'));
return teamIndicators.length < 2; // Allow some team indicators but not many
}
// Team platforms typically have more complex multi-tenant features
if (override === 'team') {
// Look for individual-specific indicators that would contradict team architecture
const individualIndicators = detectionResults.integration.recommendations.filter(rec => rec.toLowerCase().includes('individual') || rec.toLowerCase().includes('personal'));
return individualIndicators.length < 2; // Allow some individual indicators but not many
}
// Hybrid platforms should have mixed indicators
if (override === 'hybrid') {
return true; // Hybrid can accommodate most patterns
}
return true; // Default to consistent if we can't determine
}
/**
* Check if domain override is logically consistent with detected patterns
*/
isDomainLogicallyConsistent(override, detectionResults) {
// Check for domain-specific schema patterns
// Outdoor domain should have gear/setup related tables
if (override === 'outdoor') {
const hasOutdoorPatterns = detectionResults.integration.recommendations.some(rec => rec.toLowerCase().includes('gear') ||
rec.toLowerCase().includes('outdoor') ||
rec.toLowerCase().includes('setup'));
return hasOutdoorPatterns || detectionResults.domain.confidence < 0.7; // Allow if detection isn't very confident
}
// SaaS domain should have subscription/billing patterns
if (override === 'saas') {
const hasSaaSPatterns = detectionResults.integration.recommendations.some(rec => rec.toLowerCase().includes('subscription') ||
rec.toLowerCase().includes('billing') ||
rec.toLowerCase().includes('workspace'));
return hasSaaSPatterns || detectionResults.domain.confidence < 0.7;
}
// E-commerce should have product/order patterns
if (override === 'ecommerce') {
const hasEcommercePatterns = detectionResults.integration.recommendations.some(rec => rec.toLowerCase().includes('product') ||
rec.toLowerCase().includes('order') ||
rec.toLowerCase().includes('cart'));
return hasEcommercePatterns || detectionResults.domain.confidence < 0.7;
}
return true; // Default to consistent if we can't determine
}
/**
* Generate validation recommendations
*/
generateValidationRecommendations(platformValidation, domainValidation, options) {
const recommendations = [];
// Platform architecture recommendations
if (platformValidation.conflictSeverity === 'high') {
recommendations.push(`Consider reviewing platform architecture override - high confidence detection suggests '${platformValidation.detectedValue}'`);
}
else if (platformValidation.conflictSeverity === 'medium') {
recommendations.push(`Platform architecture override accepted but monitor seeding results for potential issues`);
}
// Content domain recommendations
if (domainValidation.conflictSeverity === 'high') {
recommendations.push(`Consider reviewing content domain override - high confidence detection suggests '${domainValidation.detectedValue}'`);
}
else if (domainValidation.conflictSeverity === 'medium') {
recommendations.push(`Content domain override accepted but verify domain-specific features work as expected`);
}
// General recommendations
if (platformValidation.conflictSeverity !== 'none' || domainValidation.conflictSeverity !== 'none') {
recommendations.push(`Run seeding with --verbose flag to monitor override behavior`);
recommendations.push(`Consider using fallbackToAutoDetection: true for safer override handling`);
}
if (options.strictMode && (platformValidation.conflictSeverity === 'high' || domainValidation.conflictSeverity === 'high')) {
recommendations.push(`Disable strict mode or address high-severity conflicts before proceeding`);
}
return recommendations;
}
/**
* Count total conflicts
*/
countConflicts(platformValidation, domainValidation) {
let count = 0;
if (platformValidation.conflictSeverity !== 'none')
count++;
if (domainValidation.conflictSeverity !== 'none')
count++;
return count;
}
/**
* Count high-severity conflicts
*/
countHighSeverityConflicts(platformValidation, domainValidation) {
let count = 0;
if (platformValidation.conflictSeverity === 'high')
count++;
if (domainValidation.conflictSeverity === 'high')
count++;
return count;
}
/**
* Get confidence level from score
*/
getConfidenceLevel(confidence) {
if (confidence >= 0.9)
return 'very_high';
if (confidence >= 0.7)
return 'high';
if (confidence >= 0.5)
return 'medium';
if (confidence >= 0.3)
return 'low';
return 'very_low';
}
/**
* Create failure result
*/
createFailureResult(error, executionTime) {
return {
valid: false,
confidence: 0,
confidenceLevel: 'very_low',
platformArchitecture: {
hasOverride: false,
conflictSeverity: 'high',
recommendedAction: 'reject',
validation: {
valid: false,
confidence: 0,
reasoning: [],
warnings: ['Validation failed due to error']
}
},
contentDomain: {
hasOverride: false,
conflictSeverity: 'high',
recommendedAction: 'reject',
validation: {
valid: false,
confidence: 0,
reasoning: [],
warnings: ['Validation failed due to error']
}
},
validation: {
totalConflicts: 0,
highSeverityConflicts: 0,
validationTime: executionTime,
validationMethod: 'error',
recommendations: ['Fix validation errors before proceeding'],
warnings: [`Validation error: ${error.message}`],
errors: [error.message]
}
};
}
/**
* Merge options with defaults
*/
mergeWithDefaults(options) {
return {
strictMode: false,
warningLevel: 'detailed',
confidenceThreshold: 0.7,
validateDomainSpecific: true,
checkConfigurationConsistency: true,
suggestAutoFixes: true,
...options
};
}
}
exports.OverrideValidator = OverrideValidator;
/**
* Utility functions for override validation
*/
class OverrideValidationUtils {
/**
* Check if configuration has any manual overrides
*/
static hasManualOverrides(config) {
return !!(config.detection?.platformArchitecture?.override ||
config.detection?.contentDomain?.override);
}
/**
* Extract override summary for logging
*/
static getOverrideSummary(config) {
const overrides = [];
if (config.detection?.platformArchitecture?.override) {
overrides.push(`Platform: ${config.detection.platformArchitecture.override}`);
}
if (config.detection?.contentDomain?.override) {
overrides.push(`Domain: ${config.detection.contentDomain.override}`);
}
return overrides.length > 0 ? overrides.join(', ') : 'None';
}
/**
* Create default validation options
*/
static getDefaultValidationOptions() {
return {
strictMode: false,
warningLevel: 'detailed',
confidenceThreshold: 0.7,
validateDomainSpecific: true,
checkConfigurationConsistency: true,
suggestAutoFixes: true
};
}
/**
* Format validation result for display
*/
static formatValidationResult(result) {
const lines = [];
lines.push('🔍 Override Validation Results');
lines.push('─'.repeat(40));
lines.push(`Overall Status: ${result.valid ? '✅ Valid' : '❌ Invalid'}`);
lines.push(`Confidence: ${(result.confidence * 100).toFixed(1)}%`);
lines.push(`Total Conflicts: ${result.validation.totalConflicts}`);
lines.push(`High Severity: ${result.validation.highSeverityConflicts}`);
lines.push('');
// Platform architecture section
if (result.platformArchitecture.hasOverride) {
lines.push('🏗️ Platform Architecture');
lines.push(`Override: ${result.platformArchitecture.overrideValue}`);
lines.push(`Detected: ${result.platformArchitecture.detectedValue}`);
lines.push(`Conflict: ${result.platformArchitecture.conflictSeverity}`);
lines.push(`Action: ${result.platformArchitecture.recommendedAction}`);
lines.push('');
}
// Content domain section
if (result.contentDomain.hasOverride) {
lines.push('🎯 Content Domain');
lines.push(`Override: ${result.contentDomain.overrideValue}`);
lines.push(`Detected: ${result.contentDomain.detectedValue}`);
lines.push(`Conflict: ${result.contentDomain.conflictSeverity}`);
lines.push(`Action: ${result.contentDomain.recommendedAction}`);
lines.push('');
}
// Recommendations
if (result.validation.recommendations.length > 0) {
lines.push('💡 Recommendations');
result.validation.recommendations.forEach(rec => {
lines.push(`• ${rec}`);
});
lines.push('');
}
// Warnings
if (result.validation.warnings.length > 0) {
lines.push('⚠️ Warnings');
result.validation.warnings.forEach(warning => {
lines.push(`• ${warning}`);
});
}
return lines.join('\n');
}
}
exports.OverrideValidationUtils = OverrideValidationUtils;
/**
* Default override validation options
*/
exports.DEFAULT_OVERRIDE_VALIDATION_OPTIONS = {
strictMode: false,
warningLevel: 'detailed',
confidenceThreshold: 0.7,
validateDomainSpecific: true,
checkConfigurationConsistency: true,
suggestAutoFixes: true
};
//# sourceMappingURL=override-validator.js.map