workspace/projects/trading-platform/apps/personal/scripts/validate-config.ts
rckrdmrd 513a86ceee
Some checks are pending
CI Pipeline / changes (push) Waiting to run
CI Pipeline / core (push) Blocked by required conditions
CI Pipeline / trading-backend (push) Blocked by required conditions
CI Pipeline / trading-data-service (push) Blocked by required conditions
CI Pipeline / trading-frontend (push) Blocked by required conditions
CI Pipeline / erp-core (push) Blocked by required conditions
CI Pipeline / erp-mecanicas (push) Blocked by required conditions
CI Pipeline / gamilit-backend (push) Blocked by required conditions
CI Pipeline / gamilit-frontend (push) Blocked by required conditions
Major update: orchestration system, catalog references, and multi-project enhancements
Core:
- Add catalog reference implementations (auth, payments, notifications, websocket, etc.)
- New agent profiles: Database Auditor, Integration Validator, LLM Agent, Policy Auditor, Trading Strategist
- Update SIMCO directives and add escalation/git guidelines
- Add deployment inventory and audit execution reports

Projects:
- erp-suite: DevOps configs, Dockerfiles, shared libs, vertical enhancements
- gamilit: Test structure, admin controllers, service refactoring, husky/commitlint
- trading-platform: MT4 gateway, auth controllers, admin frontend, deployment scripts
- platform_marketing_content: Full DevOps setup, tests, Docker configs
- betting-analytics/inmobiliaria-analytics: Initial app structure

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-12 22:53:55 -06:00

214 lines
7.6 KiB
TypeScript

/**
* Validate Personal Configuration Script
* Checks config.yaml for errors and completeness
*
* Usage: npx tsx scripts/validate-config.ts
*/
import * as fs from 'fs';
import * as path from 'path';
import * as yaml from 'js-yaml';
const CONFIG_PATH = path.join(__dirname, '..', 'config.yaml');
interface ValidationError {
path: string;
message: string;
severity: 'error' | 'warning';
}
const errors: ValidationError[] = [];
function addError(path: string, message: string, severity: 'error' | 'warning' = 'error'): void {
errors.push({ path, message, severity });
}
function validateEmail(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function validateConfig(config: Record<string, unknown>): void {
// Validate admin section
if (!config.admin) {
addError('admin', 'Admin section is required');
} else {
const admin = config.admin as Record<string, unknown>;
if (!admin.email || !validateEmail(admin.email as string)) {
addError('admin.email', 'Valid email is required');
}
if (!admin.role || !['admin', 'premium', 'user'].includes(admin.role as string)) {
addError('admin.role', 'Role must be one of: admin, premium, user');
}
}
// Validate risk profile
if (!config.risk_profile) {
addError('risk_profile', 'Risk profile section is required');
} else {
const rp = config.risk_profile as Record<string, unknown>;
if (typeof rp.max_risk_percent !== 'number' || rp.max_risk_percent <= 0 || rp.max_risk_percent > 100) {
addError('risk_profile.max_risk_percent', 'Must be a number between 0 and 100');
}
if (typeof rp.max_drawdown_tolerance !== 'number' || rp.max_drawdown_tolerance <= 0) {
addError('risk_profile.max_drawdown_tolerance', 'Must be a positive number');
}
}
// Validate priority assets
if (!config.priority_assets || !Array.isArray(config.priority_assets)) {
addError('priority_assets', 'Priority assets array is required');
} else {
const assets = config.priority_assets as Record<string, unknown>[];
if (assets.length === 0) {
addError('priority_assets', 'At least one priority asset is required', 'warning');
}
assets.forEach((asset, i) => {
if (!asset.symbol) {
addError(`priority_assets[${i}].symbol`, 'Symbol is required');
}
if (!asset.data_provider) {
addError(`priority_assets[${i}].data_provider`, 'Data provider is required');
}
if (typeof asset.priority !== 'number') {
addError(`priority_assets[${i}].priority`, 'Priority must be a number');
}
});
// Check for duplicate symbols
const symbols = assets.map(a => a.symbol);
const duplicates = symbols.filter((s, i) => symbols.indexOf(s) !== i);
if (duplicates.length > 0) {
addError('priority_assets', `Duplicate symbols found: ${duplicates.join(', ')}`);
}
}
// Validate trading agents
if (!config.trading_agents || !Array.isArray(config.trading_agents)) {
addError('trading_agents', 'Trading agents array is required');
} else {
const agents = config.trading_agents as Record<string, unknown>[];
agents.forEach((agent, i) => {
if (!agent.name) {
addError(`trading_agents[${i}].name`, 'Name is required');
}
if (!agent.slug) {
addError(`trading_agents[${i}].slug`, 'Slug is required');
}
if (!agent.risk_profile || !['conservative', 'moderate', 'aggressive'].includes(agent.risk_profile as string)) {
addError(`trading_agents[${i}].risk_profile`, 'Risk profile must be: conservative, moderate, or aggressive');
}
if (typeof agent.min_confidence !== 'number' || (agent.min_confidence as number) < 0 || (agent.min_confidence as number) > 1) {
addError(`trading_agents[${i}].min_confidence`, 'Min confidence must be between 0 and 1');
}
if (!agent.supported_symbols || !Array.isArray(agent.supported_symbols) || (agent.supported_symbols as string[]).length === 0) {
addError(`trading_agents[${i}].supported_symbols`, 'At least one supported symbol is required');
}
});
// Check for duplicate slugs
const slugs = agents.map(a => a.slug);
const dupSlugs = slugs.filter((s, i) => slugs.indexOf(s) !== i);
if (dupSlugs.length > 0) {
addError('trading_agents', `Duplicate slugs found: ${dupSlugs.join(', ')}`);
}
}
// Validate paper trading
if (config.paper_trading) {
const pt = config.paper_trading as Record<string, unknown>;
if (pt.enabled && typeof pt.initial_balance !== 'number') {
addError('paper_trading.initial_balance', 'Initial balance must be a number when enabled');
}
if (pt.enabled && (pt.initial_balance as number) <= 0) {
addError('paper_trading.initial_balance', 'Initial balance must be positive');
}
}
// Validate ML models
if (config.ml_models) {
const ml = config.ml_models as Record<string, unknown>;
const thresholds = ml.thresholds as Record<string, number> | undefined;
if (thresholds) {
if (typeof thresholds.min_confidence !== 'number' || thresholds.min_confidence < 0 || thresholds.min_confidence > 1) {
addError('ml_models.thresholds.min_confidence', 'Must be between 0 and 1');
}
}
}
// Validate system settings
if (config.system) {
const sys = config.system as Record<string, unknown>;
if (sys.auto_trade_enabled && !sys.auto_trade_require_confirmation) {
addError('system', 'Auto trade without confirmation is risky', 'warning');
}
}
}
async function main(): Promise<void> {
console.log('='.repeat(60));
console.log('OrbiQuant IA - Config Validation');
console.log('='.repeat(60));
console.log(`\nValidating: ${CONFIG_PATH}\n`);
try {
if (!fs.existsSync(CONFIG_PATH)) {
console.error('ERROR: config.yaml not found!');
process.exit(1);
}
const configFile = fs.readFileSync(CONFIG_PATH, 'utf8');
const config = yaml.load(configFile) as Record<string, unknown>;
validateConfig(config);
const errorCount = errors.filter(e => e.severity === 'error').length;
const warningCount = errors.filter(e => e.severity === 'warning').length;
if (errors.length > 0) {
console.log('Validation Results:\n');
const errorsList = errors.filter(e => e.severity === 'error');
if (errorsList.length > 0) {
console.log('ERRORS:');
errorsList.forEach(e => {
console.log(` [ERROR] ${e.path}: ${e.message}`);
});
}
const warningsList = errors.filter(e => e.severity === 'warning');
if (warningsList.length > 0) {
console.log('\nWARNINGS:');
warningsList.forEach(e => {
console.log(` [WARN] ${e.path}: ${e.message}`);
});
}
console.log('\n' + '-'.repeat(60));
console.log(`Summary: ${errorCount} error(s), ${warningCount} warning(s)`);
if (errorCount > 0) {
process.exit(1);
}
} else {
console.log('Config is valid!\n');
// Print summary
const admin = config.admin as Record<string, unknown>;
const assets = config.priority_assets as Record<string, unknown>[];
const agents = config.trading_agents as Record<string, unknown>[];
console.log('Configuration Summary:');
console.log(` Admin: ${admin.email}`);
console.log(` Assets: ${assets.length} priority asset(s)`);
console.log(` Agents: ${agents.length} trading agent(s)`);
console.log(` Paper Trading: ${(config.paper_trading as Record<string, unknown>).enabled ? 'Enabled' : 'Disabled'}`);
}
} catch (error) {
console.error('Validation failed:', (error as Error).message);
process.exit(1);
}
}
main();