alwas-ml-models / integration /mlBottleneckScanner.js
muthuk1's picture
Upload integration/mlBottleneckScanner.js
3ee46b0 verified
/**
* ALWAS ML-Enhanced Bottleneck Scanner
* Drop-in replacement for the existing node-cron bottleneck scanner.
* Uses ML models instead of simple 48h threshold.
*
* Place in: server/cron/mlBottleneckScanner.js
*
* Setup in server/app.js:
* const cron = require('node-cron');
* const mlScanner = require('./cron/mlBottleneckScanner');
* cron.schedule('0 * * * *', () => mlScanner(io)); // hourly
*/
const ml = require('../utils/alwas-ml-client');
const Block = require('../models/Block');
const Notification = require('../models/Notification');
const User = require('../models/User');
async function mlBottleneckScanner(io) {
console.log('[ML Scanner] Starting hourly bottleneck scan...');
try {
// Get all in-progress blocks
const blocks = await Block.find({
status: { $nin: ['Not Started', 'Completed'] }
}).populate('assignedTo');
let highRisk = 0;
let mediumRisk = 0;
let alerts = [];
for (const block of blocks) {
try {
// Calculate days in current stage
const lastTransition = block.transitions?.[block.transitions.length - 1];
const daysSince = lastTransition
? (Date.now() - new Date(lastTransition.timestamp)) / (1000 * 60 * 60 * 24)
: 0;
const riskData = ml.constructor.formatForBottleneck(block, daysSince);
const risk = await ml.predictBottleneck(riskData);
if (risk.risk_level === 'High') {
highRisk++;
// Create notification for assigned engineer
if (block.assignedTo) {
const notification = await Notification.create({
user: block.assignedTo._id || block.assignedTo,
type: 'stuck',
message: `⚠️ ML Alert: ${block.name} has HIGH bottleneck risk`,
data: {
blockId: block._id,
risk: risk.risk_level,
confidence: risk.confidence,
recommendations: risk.recommendations,
hours_over_budget: risk.hours_over_budget_ratio,
}
});
// Real-time socket notification
io.emit('newNotification', {
userId: block.assignedTo._id || block.assignedTo,
notification: notification,
});
}
// Also notify managers
const managers = await User.find({ role: 'manager' });
for (const manager of managers) {
await Notification.create({
user: manager._id,
type: 'stuck',
message: `🔴 ML Bottleneck Alert: ${block.name} (${block.status}) — ${risk.recommendations[0] || 'High risk detected'}`,
data: {
blockId: block._id,
risk: risk.risk_level,
confidence: risk.confidence,
recommendations: risk.recommendations,
engineer: block.assignedTo?.name || 'Unassigned',
}
});
}
alerts.push({
block: block.name,
stage: block.status,
risk: risk.risk_level,
confidence: risk.confidence,
reason: risk.recommendations[0] || 'High risk',
});
} else if (risk.risk_level === 'Medium') {
mediumRisk++;
}
} catch (blockError) {
console.error(`[ML Scanner] Error scanning block ${block._id}:`, blockError.message);
}
}
console.log(`[ML Scanner] Scan complete: ${blocks.length} blocks scanned, ${highRisk} high risk, ${mediumRisk} medium risk`);
if (alerts.length > 0) {
console.log('[ML Scanner] High-risk blocks:');
alerts.forEach(a => console.log(` - ${a.block} (${a.stage}): ${a.reason}`));
}
return { scanned: blocks.length, highRisk, mediumRisk, alerts };
} catch (error) {
console.error('[ML Scanner] Fatal error:', error.message);
return { error: error.message };
}
}
module.exports = mlBottleneckScanner;