Sessions 5-7a: 955 tests, deployment ready

This commit is contained in:
Kev
2026-06-08 18:35:13 -04:00
parent 06b82624a2
commit 1fa04dc776
371 changed files with 49366 additions and 955 deletions
+96
View File
@@ -0,0 +1,96 @@
const axios = require('axios');
const EVOLUTION_SERVICE_URL = process.env.EVOLUTION_SERVICE_URL || 'http://localhost:5001';
const EVOLUTION_TIMEOUT = 5000;
const TRACKED_SIGNALS = [
'usage_rate',
'assist_rate',
'three_pt_attempt_rate',
'shot_location',
'aggression_score',
'minutes_trajectory',
];
/**
* Detect changepoints in a player metric time series via Python PELT microservice.
* @param {string} playerId
* @param {string} metric - Metric name
* @param {Array<number>} values - Time series values
* @param {Array<string>} timestamps - ISO timestamps
* @returns {object} Changepoint result or graceful degradation
*/
async function detectChangepoints(playerId, metric, values, timestamps) {
try {
const response = await axios.post(
`${EVOLUTION_SERVICE_URL}/detect`,
{ player_id: playerId, metric, values, timestamps },
{ timeout: EVOLUTION_TIMEOUT }
);
return response.data;
} catch (error) {
const reason = error.code === 'ECONNABORTED'
? 'timeout'
: error.response
? `HTTP ${error.response.status}`
: error.message;
return {
evolution_detected: false,
error: reason,
playerId,
metric,
};
}
}
/**
* Check if multiple signals are inflecting simultaneously.
* If 2+ signals inflecting above 70% confidence, evolution is detected.
* @param {object} playerMetrics - { signal_name: { values, timestamps, confidence } }
* @returns {object} { evolution_detected, confidence, signals }
*/
async function checkMultiSignalEvolution(playerMetrics) {
const results = [];
for (const signal of TRACKED_SIGNALS) {
if (playerMetrics[signal]) {
const { values, timestamps } = playerMetrics[signal];
const result = await detectChangepoints(
playerMetrics.playerId,
signal,
values,
timestamps
);
if (result && !result.error) {
results.push({ signal, ...result });
}
}
}
const inflecting = results.filter(r => r.confidence >= 0.70);
if (inflecting.length >= 2) {
const avgConfidence = inflecting.reduce((s, r) => s + r.confidence, 0) / inflecting.length;
return {
evolution_detected: true,
confidence: Math.round(avgConfidence * 100) / 100,
signals: inflecting.map(r => r.signal),
details: inflecting,
};
}
return {
evolution_detected: false,
confidence: 0,
signals: [],
checked: TRACKED_SIGNALS.filter(s => playerMetrics[s]),
};
}
module.exports = {
EVOLUTION_SERVICE_URL,
EVOLUTION_TIMEOUT,
TRACKED_SIGNALS,
detectChangepoints,
checkMultiSignalEvolution,
};