05_14_04 - Validation System (Extended)¶
Overview¶
The Validation System extends the base SchemaValidator from the Preset Schemas subsystem with advanced validation capabilities:
- Cross-preset validation - Validate relationships between multiple presets
- Dependency validation - Verify resource dependencies and module dependencies
- Rule engine - Custom validation rules with severity levels
- Batch validation - Validate preset banks efficiently
- Report generation - Detailed validation reports with actionable insights
This subsystem builds on top of 05_14_00_preset_schemas and integrates with 05_14_03_resource_management.
Architecture¶
┌─────────────────────────────────────────────────────────────┐
│ Validation System │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Base Validator │──────│ Schema Validator │ │
│ │ (from TAREA 1) │ │ (structure) │ │
│ └─────────────────┘ └─────────────────┘ │
│ │ │
│ ├──────────────────────────────────┐ │
│ │ │ │
│ ┌────────▼────────┐ ┌─────────▼──────────┐ │
│ │ Cross-Preset │ │ Dependency │ │
│ │ Validator │ │ Validator │ │
│ │ │ │ │ │
│ │ • Bank checks │ │ • Resources exist │ │
│ │ • Duplicates │ │ • Modules compat │ │
│ │ • Conflicts │ │ • Circular deps │ │
│ └─────────────────┘ └────────────────────┘ │
│ │ │ │
│ └──────────┬───────────────────────┘ │
│ │ │
│ ┌─────────▼──────────┐ │
│ │ Rules Engine │ │
│ │ │ │
│ │ • Custom rules │ │
│ │ • Severity levels │ │
│ │ • Auto-fix hints │ │
│ └────────────────────┘ │
│ │ │
│ ┌─────────▼──────────┐ │
│ │ Validation Report │ │
│ │ │ │
│ │ • Errors/Warnings │ │
│ │ • Statistics │ │
│ │ • Recommendations │ │
│ └────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Components¶
1. CrossPresetValidator¶
Validates relationships and consistency across multiple presets:
Checks: - Duplicate detection - Find presets with identical content - Name conflicts - Detect name collisions in same bank - Category consistency - Verify category/tag usage - Version compatibility - Check version mismatches in bank - Dependency chains - Validate preset dependencies
Example:
CrossPresetValidator validator;
std::vector<PresetSchema> bank = loadPresetBank("my_bank.json");
// Validate entire bank
auto result = validator.validateBank(bank);
if (!result.isValid()) {
for (const auto& error : result.errors) {
std::cout << "Error: " << error.message << "\n";
}
}
// Check for duplicates
auto duplicates = validator.findDuplicates(bank);
std::cout << "Found " << duplicates.size() << " duplicate groups\n";
// Check for conflicts
auto conflicts = validator.findConflicts(bank);
2. DependencyValidator¶
Validates resource and module dependencies:
Resource Validation: - All referenced resources exist or have fallbacks - Resource types match declared types - Checksums match if specified - No circular resource dependencies
Module Validation: - Required modules are available - Module versions are compatible - Module dependencies are satisfied - No circular module dependencies
Example:
DependencyValidator validator(resource_manager);
// Validate single preset dependencies
auto result = validator.validatePresetDependencies(preset);
if (result.missing_resources.size() > 0) {
std::cout << "Missing resources:\n";
for (const auto& res : result.missing_resources) {
std::cout << " - " << res.path << "\n";
// Find alternatives
auto alternatives = validator.findResourceAlternatives(res);
for (const auto& alt : alternatives) {
std::cout << " → " << alt.path << " (similarity: "
<< alt.similarity << ")\n";
}
}
}
// Check circular dependencies
if (validator.hasCircularDependencies(presets)) {
auto cycles = validator.findCircularDependencies(presets);
// ...
}
3. ValidationRulesEngine¶
Extensible rule-based validation system:
Built-in Rules: - Parameter range validation - Parameter consistency checks (e.g., filter cutoff vs resonance) - Naming conventions - Metadata completeness - Performance characteristics (e.g., CPU usage estimates)
Custom Rules:
class MyCustomRule : public ValidationRule {
public:
ValidationResult validate(const PresetSchema& preset) override {
ValidationResult result;
// Custom validation logic
if (preset.header.name.length() > 50) {
result.addWarning("Name too long (max 50 chars)");
}
return result;
}
std::string getName() const override { return "NameLengthRule"; }
Severity getSeverity() const override { return Severity::Warning; }
};
// Register rule
ValidationRulesEngine engine;
engine.registerRule(std::make_unique<MyCustomRule>());
// Validate with all rules
auto result = engine.validate(preset);
Rule Severity Levels: - Critical - Prevents preset from loading (e.g., corrupt data) - Error - Invalid preset, may cause issues (e.g., missing required field) - Warning - Valid but potentially problematic (e.g., unusual values) - Info - Informational message (e.g., optimization suggestion)
4. BatchValidator¶
Efficient validation of large preset collections:
Features: - Parallel validation (multi-threaded) - Progress callbacks - Incremental validation (only changed presets) - Validation caching - Summary reports
Example:
BatchValidator validator;
validator.setThreadCount(8); // Use 8 threads
// Progress callback
validator.setProgressCallback([](size_t current, size_t total) {
std::cout << "Validating: " << current << "/" << total << "\r";
});
// Validate large bank
std::vector<PresetSchema> bank = loadLargeBank("factory.json"); // 1000 presets
auto report = validator.validateBatch(bank);
std::cout << "\nValidation Summary:\n";
std::cout << " Total: " << report.total_presets << "\n";
std::cout << " Valid: " << report.valid_presets << "\n";
std::cout << " Warnings: " << report.warning_count << "\n";
std::cout << " Errors: " << report.error_count << "\n";
std::cout << " Time: " << report.validation_time_ms << "ms\n";
5. ValidationReport¶
Structured validation results with actionable insights:
Report Contents: - Errors - Issues that must be fixed - Warnings - Issues that should be reviewed - Info - Informational messages - Statistics - Validation metrics - Recommendations - Auto-fix suggestions
Report Formats: - Console - Human-readable text output - JSON - Machine-readable structured data - HTML - Rich formatted report with navigation - Markdown - Documentation-friendly format
Example:
ValidationReport report = validator.validate(preset);
// Console output
std::cout << report.toConsole();
// JSON export
std::ofstream json_file("validation_report.json");
json_file << report.toJSON();
// HTML report
std::ofstream html_file("validation_report.html");
html_file << report.toHTML();
// Get auto-fix suggestions
for (const auto& fix : report.getAutoFixSuggestions()) {
std::cout << "Suggestion: " << fix.description << "\n";
if (fix.can_auto_fix) {
std::cout << " Can auto-fix: Yes\n";
// Apply fix
fix.apply(preset);
}
}
Validation Levels¶
The system supports multiple validation levels that can be configured:
Level 1: Quick (Structure Only)¶
- JSON/Binary structure valid
- Required fields present
- Type checking
- Performance: <1ms per preset
Level 2: Standard (+ Basic Validation)¶
- Level 1 checks
- Parameter ranges
- Basic consistency
- Performance: ~5ms per preset
Level 3: Extended (+ Cross-Preset)¶
- Level 2 checks
- Duplicate detection
- Name conflicts
- Performance: ~10ms per preset
Level 4: Full (+ Dependencies)¶
- Level 3 checks
- Resource validation
- Module compatibility
- Performance: ~20ms per preset
Level 5: Comprehensive (+ Rules Engine)¶
- Level 4 checks
- All custom rules
- Auto-fix suggestions
- Performance: ~50ms per preset
Configuration:
ValidationConfig config;
config.level = ValidationLevel::Full;
config.enable_auto_fix = false;
config.parallel_validation = true;
config.cache_results = true;
Validator validator(config);
Integration with Other Subsystems¶
With Resource Management (TAREA 4)¶
// Create validator with resource manager integration
ResourceManager resource_manager;
DependencyValidator dep_validator(resource_manager);
// Validate preset - will check if resources exist
auto result = dep_validator.validatePresetDependencies(preset);
// Auto-fix: Use resource manager to find alternatives
if (!result.missing_resources.empty()) {
for (const auto& missing : result.missing_resources) {
auto similar = resource_manager.findSimilarResources(missing);
if (!similar.empty()) {
preset.replaceResource(missing, similar[0]);
}
}
}
With Version Management (TAREA 3)¶
// Check version compatibility in bank
CrossPresetValidator validator;
auto bank = loadPresetBank("mixed_versions.json");
auto version_issues = validator.findVersionMismatches(bank);
if (!version_issues.empty()) {
VersionManager& vm = VersionManager::getInstance();
// Migrate all to latest version
for (auto& preset : bank) {
if (preset.header.version != vm.getCurrentVersion()) {
preset = vm.migrate(preset, vm.getCurrentVersion());
}
}
}
With Serialization (TAREA 2)¶
// Validate before serialization
PresetSchema preset = createPreset();
Validator validator;
auto result = validator.validate(preset);
if (result.isValid()) {
// Safe to serialize
JSONSerializer serializer;
serializer.serializeToFile(preset, "preset.json");
} else {
// Try auto-fix
result.applyAutoFixes(preset);
// Re-validate
result = validator.validate(preset);
if (result.isValid()) {
serializer.serializeToFile(preset, "preset.json");
} else {
std::cerr << "Cannot save invalid preset\n";
}
}
API Reference¶
CrossPresetValidator¶
class CrossPresetValidator {
public:
// Bank validation
ValidationResult validateBank(const std::vector<PresetSchema>& bank);
// Duplicate detection
std::vector<DuplicateGroup> findDuplicates(
const std::vector<PresetSchema>& bank);
// Conflict detection
std::vector<Conflict> findConflicts(
const std::vector<PresetSchema>& bank);
// Version consistency
std::vector<VersionMismatch> findVersionMismatches(
const std::vector<PresetSchema>& bank);
// Category validation
ValidationResult validateCategories(
const std::vector<PresetSchema>& bank);
};
DependencyValidator¶
class DependencyValidator {
public:
// Constructor with resource manager
explicit DependencyValidator(ResourceManager& resource_manager);
// Resource dependency validation
DependencyResult validatePresetDependencies(const PresetSchema& preset);
// Module dependency validation
DependencyResult validateModuleDependencies(const PresetSchema& preset);
// Circular dependency detection
bool hasCircularDependencies(const std::vector<PresetSchema>& presets);
std::vector<DependencyCircle> findCircularDependencies(
const std::vector<PresetSchema>& presets);
// Find alternatives for missing resources
std::vector<ResourceAlternative> findResourceAlternatives(
const PresetSchema::ResourceRef& resource);
};
ValidationRulesEngine¶
class ValidationRulesEngine {
public:
// Rule management
void registerRule(std::unique_ptr<ValidationRule> rule);
void unregisterRule(const std::string& rule_name);
// Validation
ValidationResult validate(const PresetSchema& preset);
ValidationResult validateWithRules(
const PresetSchema& preset,
const std::vector<std::string>& rule_names);
// Rule queries
std::vector<std::string> getRegisteredRules() const;
const ValidationRule* getRule(const std::string& name) const;
};
// Base class for custom rules
class ValidationRule {
public:
virtual ~ValidationRule() = default;
virtual ValidationResult validate(const PresetSchema& preset) = 0;
virtual std::string getName() const = 0;
virtual Severity getSeverity() const = 0;
virtual std::string getDescription() const = 0;
};
BatchValidator¶
class BatchValidator {
public:
// Configuration
void setThreadCount(size_t count);
void setValidationLevel(ValidationLevel level);
void setProgressCallback(ProgressCallback callback);
// Batch validation
BatchValidationReport validateBatch(
const std::vector<PresetSchema>& presets);
// Incremental validation (only changed presets)
BatchValidationReport validateIncremental(
const std::vector<PresetSchema>& presets,
const std::vector<std::string>& changed_ids);
// Cache management
void clearCache();
void setCacheEnabled(bool enabled);
};
ValidationReport¶
class ValidationReport {
public:
// Status
bool isValid() const;
bool hasErrors() const;
bool hasWarnings() const;
// Counts
size_t getErrorCount() const;
size_t getWarningCount() const;
size_t getInfoCount() const;
// Messages
const std::vector<ValidationMessage>& getErrors() const;
const std::vector<ValidationMessage>& getWarnings() const;
const std::vector<ValidationMessage>& getInfo() const;
// Export
std::string toConsole() const;
std::string toJSON() const;
std::string toHTML() const;
std::string toMarkdown() const;
// Auto-fix
std::vector<AutoFixSuggestion> getAutoFixSuggestions() const;
void applyAutoFixes(PresetSchema& preset);
};
Performance Targets¶
| Operation | Target | Notes |
|---|---|---|
| Quick validation (L1) | <1ms | Structure only |
| Standard validation (L2) | <5ms | + Basic checks |
| Full validation (L4) | <20ms | + Dependencies |
| Batch validation (1000) | <5s | Parallel, 8 threads |
| Duplicate detection (1000) | <100ms | Hash-based |
| Circular dependency check | O(n²) | DFS algorithm |
Usage Examples¶
Example 1: Validate Single Preset¶
#include <validation_system.hpp>
PresetSchema preset = loadPreset("my_preset.json");
// Create validator with standard level
ValidationConfig config;
config.level = ValidationLevel::Standard;
Validator validator(config);
// Validate
auto report = validator.validate(preset);
if (report.isValid()) {
std::cout << "✓ Preset is valid\n";
} else {
std::cout << "✗ Preset has issues:\n";
for (const auto& error : report.getErrors()) {
std::cout << " [ERROR] " << error.message << "\n";
}
for (const auto& warning : report.getWarnings()) {
std::cout << " [WARN] " << warning.message << "\n";
}
}
Example 2: Validate Preset Bank¶
// Load bank
std::vector<PresetSchema> bank = loadPresetBank("factory.json");
// Create cross-preset validator
CrossPresetValidator validator;
// Find duplicates
auto duplicates = validator.findDuplicates(bank);
std::cout << "Found " << duplicates.size() << " duplicate groups\n";
for (const auto& group : duplicates) {
std::cout << "Duplicates:\n";
for (const auto& preset : group.presets) {
std::cout << " - " << preset.header.name << "\n";
}
}
// Find conflicts
auto conflicts = validator.findConflicts(bank);
for (const auto& conflict : conflicts) {
std::cout << "Conflict: " << conflict.description << "\n";
std::cout << " Between: " << conflict.preset1_id
<< " and " << conflict.preset2_id << "\n";
}
Example 3: Custom Validation Rule¶
class CPUUsageRule : public ValidationRule {
public:
ValidationResult validate(const PresetSchema& preset) override {
ValidationResult result;
// Estimate CPU usage
float cpu_estimate = estimateCPU(preset);
if (cpu_estimate > 80.0f) {
result.addWarning(
"High CPU usage estimated: " +
std::to_string(cpu_estimate) + "%"
);
// Add auto-fix suggestion
result.addAutoFix(
"Consider reducing oversampling or filter order"
);
}
return result;
}
std::string getName() const override { return "CPUUsageRule"; }
Severity getSeverity() const override { return Severity::Warning; }
private:
float estimateCPU(const PresetSchema& preset) {
// Simple heuristic based on parameter values
float cpu = 0.0f;
// Check for expensive operations
if (preset.parameters.find("oversampling") != preset.parameters.end()) {
cpu += preset.parameters.at("oversampling").value * 10.0f;
}
if (preset.parameters.find("filter.order") != preset.parameters.end()) {
cpu += preset.parameters.at("filter.order").value * 5.0f;
}
return cpu;
}
};
// Use the rule
ValidationRulesEngine engine;
engine.registerRule(std::make_unique<CPUUsageRule>());
auto result = engine.validate(preset);
Best Practices¶
1. Choose Appropriate Validation Level¶
- Use Quick during interactive editing
- Use Standard for save operations
- Use Full for bank imports
- Use Comprehensive for quality assurance
2. Handle Validation Results Gracefully¶
auto result = validator.validate(preset);
if (!result.isValid()) {
// Try auto-fix first
if (result.hasAutoFixes()) {
result.applyAutoFixes(preset);
result = validator.validate(preset);
}
// If still invalid, notify user
if (!result.isValid()) {
showValidationErrorsDialog(result);
return;
}
}
// Proceed with valid preset
savePreset(preset);
3. Use Batch Validation for Large Collections¶
BatchValidator validator;
validator.setThreadCount(std::thread::hardware_concurrency());
validator.setValidationLevel(ValidationLevel::Standard);
auto report = validator.validateBatch(bank);
// Process results
for (const auto& preset_result : report.preset_results) {
if (!preset_result.isValid()) {
std::cout << preset_result.preset_id << ": "
<< preset_result.error_count << " errors\n";
}
}
4. Cache Validation Results¶
BatchValidator validator;
validator.setCacheEnabled(true);
// First validation (slow)
auto report1 = validator.validateBatch(bank);
// Modify some presets
bank[0].parameters["gain"].value = 0.5f;
// Incremental validation (fast - only changed presets)
auto report2 = validator.validateIncremental(bank, {"preset_0"});
Files¶
05_14_04_validation_system/
├── include/
│ ├── cross_preset_validator.hpp
│ ├── dependency_validator.hpp
│ ├── validation_rules_engine.hpp
│ ├── batch_validator.hpp
│ └── validation_report.hpp
├── src/
│ ├── cross_preset_validator.cpp
│ ├── dependency_validator.cpp
│ ├── validation_rules_engine.cpp
│ ├── batch_validator.cpp
│ └── validation_report.cpp
├── tests/
│ ├── test_cross_preset_validator.cpp
│ ├── test_dependency_validator.cpp
│ ├── test_validation_rules.cpp
│ └── test_batch_validator.cpp
├── examples/
│ ├── validate_preset_example.cpp
│ ├── validate_bank_example.cpp
│ ├── custom_rule_example.cpp
│ └── batch_validation_example.cpp
├── CMakeLists.txt
└── README.md (this file)
Dependencies¶
- 05_14_00_preset_schemas - Base schemas and SchemaValidator
- 05_14_03_resource_management - Resource validation
- nlohmann/json - JSON handling
- Catch2 - Testing framework
Notes¶
- This subsystem extends but does not replace the base
SchemaValidator - Focus is on higher-level validation (cross-preset, dependencies, rules)
- Designed for extensibility - easy to add custom rules
- Performance-conscious - parallel validation, caching
- Integration-ready - works with all other subsystems