yoda-mcp
Version:
Intelligent Planning MCP with Optional Dependencies and Graceful Fallbacks - wise planning through the Force of lean excellence
440 lines (383 loc) • 16.8 kB
text/typescript
/**
* SmartResourceOptimizer Tests
*
* RED PHASE: Write failing tests for genuine Pareto analysis
* These tests define what real resource optimization means (not hardcoded sorting)
*/
import { SmartResourceOptimizer } from '../src/smart/smart-resource-optimizer';
import { Plan, Task, ProjectContext, ParetoAnalysis } from '../src/types';
describe('SmartResourceOptimizer', () => {
let optimizer: SmartResourceOptimizer;
beforeEach(() => {
optimizer = new SmartResourceOptimizer();
});
// RED: This test MUST fail - SmartResourceOptimizer doesn't exist yet
describe('Dynamic Business Value Analysis', () => {
test('should calculate higher value for user-facing features', () => {
const userFacingTask: Task = {
id: 'user_dashboard',
title: 'Build user dashboard',
description: 'Main interface users interact with daily',
estimatedHours: 12,
skills: ['frontend'],
dependencies: [],
deliverable: 'Dashboard UI'
};
const internalTask: Task = {
id: 'logging_system',
title: 'Implement logging',
description: 'Internal system for error tracking',
estimatedHours: 8,
skills: ['backend'],
dependencies: [],
deliverable: 'Logging service'
};
const context: ProjectContext = {
userPriorities: ['usability', 'performance'],
timeline: 'normal',
businessModel: 'saas',
industry: 'technology'
};
const userValue = optimizer.calculateBusinessValue(userFacingTask, context);
const internalValue = optimizer.calculateBusinessValue(internalTask, context);
expect(userValue).toBeGreaterThan(internalValue);
expect(userValue).toBeGreaterThanOrEqual(80); // User-facing should be high value
expect(internalValue).toBeLessThan(70); // Internal should be lower value
});
test('should calculate higher value for revenue-impacting features', () => {
const paymentTask: Task = {
id: 'payment_processing',
title: 'Implement payment system',
description: 'Process customer payments and subscriptions',
estimatedHours: 16,
skills: ['backend', 'payments'],
dependencies: [],
deliverable: 'Payment system'
};
const documentationTask: Task = {
id: 'api_docs',
title: 'Write API documentation',
description: 'Document REST API endpoints',
estimatedHours: 6,
skills: ['documentation'],
dependencies: [],
deliverable: 'API documentation'
};
const context: ProjectContext = {
userPriorities: [],
timeline: 'normal',
businessModel: 'ecommerce',
industry: 'retail'
};
const paymentValue = optimizer.calculateBusinessValue(paymentTask, context);
const docsValue = optimizer.calculateBusinessValue(documentationTask, context);
expect(paymentValue).toBeGreaterThan(docsValue);
expect(paymentValue).toBeGreaterThanOrEqual(90); // Revenue impact should be very high
});
test('should adjust value based on industry context', () => {
const securityTask: Task = {
id: 'security_audit',
title: 'Security compliance audit',
description: 'Implement security controls and audit logging',
estimatedHours: 20,
skills: ['security', 'compliance'],
dependencies: [],
deliverable: 'Compliance report'
};
const financialContext: ProjectContext = {
userPriorities: [],
timeline: 'normal',
businessModel: 'saas',
industry: 'financial' // High security requirements
};
const techContext: ProjectContext = {
userPriorities: [],
timeline: 'normal',
businessModel: 'saas',
industry: 'technology' // Lower security requirements
};
const financialValue = optimizer.calculateBusinessValue(securityTask, financialContext);
const techValue = optimizer.calculateBusinessValue(securityTask, techContext);
expect(financialValue).toBeGreaterThan(techValue);
expect(financialValue).toBeGreaterThanOrEqual(85); // Critical for financial industry
});
});
// RED: This test MUST fail - calculateRealEffort doesn't exist yet
describe('Real Effort Calculation', () => {
test('should adjust effort based on task complexity type', () => {
const integrationTask: Task = {
id: 'legacy_integration',
title: 'Integrate with legacy system',
description: 'Connect new API to old mainframe system',
estimatedHours: 10,
skills: ['integration', 'legacy'],
dependencies: [],
deliverable: 'Integration layer'
};
const simpleTask: Task = {
id: 'ui_update',
title: 'Update button color',
description: 'Change primary button from blue to green',
estimatedHours: 2,
skills: ['ui'],
dependencies: [],
deliverable: 'Updated button'
};
const integrationEffort = optimizer.calculateRealEffort(integrationTask);
const simpleEffort = optimizer.calculateRealEffort(simpleTask);
expect(integrationEffort).toBeGreaterThan(integrationTask.estimatedHours); // Should be multiplied
expect(simpleEffort).toBeLessThanOrEqual(simpleTask.estimatedHours * 1.2); // Minimal multiplier
expect(integrationEffort / integrationTask.estimatedHours).toBeGreaterThan(1.4); // At least 40% increase
});
test('should consider team experience in effort calculation', () => {
const complexTask: Task = {
id: 'ml_model',
title: 'Build machine learning model',
description: 'Train ML model for recommendation system',
estimatedHours: 40,
skills: ['machine-learning', 'python', 'data-science'],
dependencies: [],
deliverable: 'ML model'
};
const experiencedTeamMultiplier = 0.8; // Team has ML experience
const inexperiencedTeamMultiplier = 2.0; // Team is new to ML
optimizer.setTeamExperienceMultiplier('machine-learning', experiencedTeamMultiplier);
const experiencedEffort = optimizer.calculateRealEffort(complexTask);
optimizer.setTeamExperienceMultiplier('machine-learning', inexperiencedTeamMultiplier);
const inexperiencedEffort = optimizer.calculateRealEffort(complexTask);
expect(inexperiencedEffort).toBeGreaterThan(experiencedEffort);
expect(inexperiencedEffort / experiencedEffort).toBeGreaterThanOrEqual(2.0);
});
});
// RED: This test MUST fail - analyzeParetoImpact doesn't exist yet
describe('True Pareto Analysis', () => {
test('should find actual 80% value threshold, not just top 20% of tasks', async () => {
const tasks: Task[] = [
// These 2 tasks should deliver 80%+ of total value (true Pareto)
{
id: 'core_feature',
title: 'Core product feature',
description: 'Main value proposition',
estimatedHours: 20,
skills: [],
dependencies: [],
deliverable: 'Core feature',
businessValue: 50 // Will be calculated dynamically
},
{
id: 'payment_system',
title: 'Payment processing',
description: 'Revenue generation',
estimatedHours: 16,
skills: [],
dependencies: [],
deliverable: 'Payments',
businessValue: 40 // Will be calculated dynamically
},
// These 3 tasks should deliver remaining 20% of value
{
id: 'admin_panel',
title: 'Admin interface',
description: 'Internal admin tools',
estimatedHours: 12,
skills: [],
dependencies: [],
deliverable: 'Admin panel',
businessValue: 6 // Will be calculated dynamically
},
{
id: 'reports',
title: 'Reporting system',
description: 'Generate usage reports',
estimatedHours: 8,
skills: [],
dependencies: [],
deliverable: 'Reports',
businessValue: 3 // Will be calculated dynamically
},
{
id: 'documentation',
title: 'User documentation',
description: 'Help and tutorial content',
estimatedHours: 6,
skills: [],
dependencies: [],
deliverable: 'Docs',
businessValue: 1 // Will be calculated dynamically
}
];
const plan: Plan = {
requirements: [],
tasks,
timeline: { totalEstimate: '8 weeks', phases: [], criticalPath: [] },
risks: [],
metadata: { planId: 'pareto_test', generatedAt: new Date(), estimatedReadTime: '10 min', complexity: 'moderate' }
};
const context: ProjectContext = {
userPriorities: ['core-functionality', 'revenue'],
timeline: 'normal',
businessModel: 'saas',
industry: 'technology'
};
const analysis: ParetoAnalysis = await optimizer.analyzeParetoImpact(plan, context);
// Should identify true vital tasks (not just 20% of count)
expect(analysis.vitalTasks).toHaveLength(2); // Should be 2, not Math.ceil(5 * 0.2) = 1
expect(analysis.vitalTasks.map(t => t.id)).toContain('core_feature');
expect(analysis.vitalTasks.map(t => t.id)).toContain('payment_system');
// Should achieve true 80% value concentration
expect(analysis.valueConcentration).toBeGreaterThanOrEqual(0.8);
// Actual Pareto ratio should be 40% (2 out of 5), not forced 20%
expect(analysis.actualParetoRatio).toBeCloseTo(0.4, 1);
// Should provide actionable recommendations
expect(analysis.recommendations.some(rec => rec.includes('low-ROI'))).toBe(true);
expect(analysis.recommendations.length).toBeGreaterThan(0);
});
test('should handle edge case where all tasks have similar value', async () => {
const similarValueTasks: Task[] = Array.from({ length: 5 }, (_, i) => ({
id: `task_${i + 1}`,
title: `Similar task ${i + 1}`,
description: 'All tasks have similar business value',
estimatedHours: 8,
skills: [],
dependencies: [],
deliverable: `Output ${i + 1}`,
businessValue: 20 // All similar value
}));
const plan: Plan = {
requirements: [],
tasks: similarValueTasks,
timeline: { totalEstimate: '5 weeks', phases: [], criticalPath: [] },
risks: [],
metadata: { planId: 'similar_value', generatedAt: new Date(), estimatedReadTime: '6 min', complexity: 'simple' }
};
const context: ProjectContext = {
userPriorities: [],
timeline: 'normal',
businessModel: 'saas',
industry: 'technology'
};
const analysis: ParetoAnalysis = await optimizer.analyzeParetoImpact(plan, context);
// When values are similar, should recommend focusing on efficiency
expect(analysis.recommendations.some(rec => rec.includes('similar value'))).toBe(true);
expect(analysis.actualParetoRatio).toBeGreaterThanOrEqual(0.8); // Most tasks needed for 80% value
expect(analysis.vitalTasks.length).toBeGreaterThanOrEqual(4); // Most tasks are vital
});
});
// RED: This test MUST fail - generateResourceRecommendations doesn't exist yet
describe('Actionable Resource Recommendations', () => {
test('should provide specific guidance based on Pareto analysis results', () => {
const analysis: ParetoAnalysis = {
vitalTasks: [
{ id: 'vital_1', title: 'Vital Task 1', businessValue: 60, effortComplexity: 10, roi: 6.0 },
{ id: 'vital_2', title: 'Vital Task 2', businessValue: 40, effortComplexity: 15, roi: 2.67 }
],
importantTasks: [
{ id: 'important_1', title: 'Important Task 1', businessValue: 15, effortComplexity: 20, roi: 0.75 }
],
trivialTasks: [
{ id: 'trivial_1', title: 'Trivial Task 1', businessValue: 5, effortComplexity: 25, roi: 0.2 }
],
actualParetoRatio: 0.5, // 2 out of 4 tasks
valueConcentration: 0.83, // 100 out of 120 total value
effortRequired: 0.42, // 25 out of 60 total effort
recommendations: [] // Will be generated
};
const recommendations = optimizer.generateResourceRecommendations(
analysis.vitalTasks,
[...analysis.vitalTasks, ...analysis.importantTasks, ...analysis.trivialTasks]
);
expect(recommendations.some(rec => rec.includes('36% of effort'))).toBe(true); // Actual efficiency
expect(recommendations.length).toBeGreaterThan(0);
// Should identify low-ROI tasks to defer
expect(recommendations.some(rec => rec.includes('low-ROI'))).toBe(true);
expect(recommendations.some(rec => rec.includes('trivial_1'))).toBe(true);
});
test('should warn when vital tasks require too much effort', () => {
const analysis: ParetoAnalysis = {
vitalTasks: [
{ id: 'complex_vital', title: 'Complex Vital Task', businessValue: 80, effortComplexity: 50, roi: 1.6 }
],
importantTasks: [
{ id: 'simple_important', title: 'Simple Important Task', businessValue: 15, effortComplexity: 5, roi: 3.0 }
],
trivialTasks: [
{ id: 'simple_trivial', title: 'Simple Trivial Task', businessValue: 5, effortComplexity: 5, roi: 1.0 }
],
actualParetoRatio: 0.33, // 1 out of 3 tasks
valueConcentration: 0.8, // 80 out of 100 total value
effortRequired: 0.83, // 50 out of 60 total effort - TOO HIGH
recommendations: []
};
const recommendations = optimizer.generateResourceRecommendations(
analysis.vitalTasks,
[...analysis.vitalTasks, ...analysis.importantTasks, ...analysis.trivialTasks]
);
expect(recommendations.some(rec => rec.includes('Warning'))).toBe(true);
expect(recommendations.some(rec => rec.includes('83% of effort'))).toBe(true);
expect(recommendations.some(rec => rec.includes('scope reduction'))).toBe(true);
});
});
// RED: This test MUST fail - contextual adaptation doesn't exist yet
describe('Context-Aware Value Calculation', () => {
test('should adapt recommendations based on timeline urgency', () => {
const task: Task = {
id: 'feature_x',
title: 'Complex feature',
description: 'Feature that takes significant development time',
estimatedHours: 40,
skills: ['full-stack'],
dependencies: [],
deliverable: 'Complex feature'
};
const urgentContext: ProjectContext = {
userPriorities: [],
timeline: 'urgent', // Urgent timeline
businessModel: 'saas',
industry: 'technology'
};
const normalContext: ProjectContext = {
userPriorities: [],
timeline: 'normal', // Normal timeline
businessModel: 'saas',
industry: 'technology'
};
const urgentValue = optimizer.calculateBusinessValue(task, urgentContext);
const normalValue = optimizer.calculateBusinessValue(task, normalContext);
// If it's on the critical path for urgent timeline, value should increase
if (optimizer.isOnCriticalPath(task)) {
expect(urgentValue).toBeGreaterThan(normalValue);
} else {
// If not on critical path, urgent timeline might decrease value (delay other priorities)
expect(urgentValue).toBeLessThanOrEqual(normalValue);
}
});
test('should provide different recommendations for different business models', () => {
const tasks = [
{
id: 'analytics',
title: 'User analytics',
description: 'Track user behavior',
estimatedHours: 12,
skills: [],
dependencies: [],
deliverable: 'Analytics system'
}
];
const saasContext: ProjectContext = {
userPriorities: [],
timeline: 'normal',
businessModel: 'saas', // Analytics important for retention
industry: 'technology'
};
const ecommerceContext: ProjectContext = {
userPriorities: [],
timeline: 'normal',
businessModel: 'ecommerce', // Analytics less critical than payment/inventory
industry: 'retail'
};
const saasValue = optimizer.calculateBusinessValue(tasks[0], saasContext);
const ecommerceValue = optimizer.calculateBusinessValue(tasks[0], ecommerceContext);
expect(saasValue).toBeGreaterThanOrEqual(ecommerceValue + 5); // At least 5 points difference
});
});
});