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
@@ -0,0 +1,154 @@
/**
* Per-grade-tier accuracy tracking.
*
* Every resolution increments counters for (sport, grade, period).
* The "all_time" period is the canonical record; "last_30d" and
* "last_7d" are derived views recomputed by a periodic refresh job
* (n8n). We update all three counters on every resolve so callers can
* read instant values without rolling a window themselves.
*
* BASELINE LOCK:
* After a (sport, grade, 'all_time') accumulates 100 decisive
* resolutions (hits + misses, not push/void), the hit rate at that
* moment is locked as `baseline_hit_rate` and `baseline_locked`
* flips to true. Future accuracy compares to the baseline to detect
* drift.
*
* EXPECTED HIT RATES (from spec):
* A+ ≥ 65%, A ≥ 60%, A- ≥ 58%, B+ ≥ 55%, B ≥ 53%, B- ≥ 51%
* C+ ≈ 50%, C ≈ 48%, C- ≈ 45%, D ≈ 40%, F ≈ 35%
*/
const { getSupabaseServiceClient } = require('../../utils/supabase');
const BASELINE_LOCK_AT = 100;
const PERIODS = ['all_time', 'last_30d', 'last_7d'];
const EXPECTED_HIT_RATES = Object.freeze({
'A+': 0.65, 'A': 0.60, 'A-': 0.58,
'B+': 0.55, 'B': 0.53, 'B-': 0.51,
'C+': 0.50, 'C': 0.48, 'C-': 0.45,
'D': 0.40, 'F': 0.35,
});
function computeHitRate(hit, miss) {
const denom = hit + miss;
return denom > 0 ? hit / denom : null;
}
async function fetchRow(supabase, sport, grade, period) {
const { data, error } = await supabase
.from('accuracy_tracking')
.select('*')
.eq('sport', sport)
.eq('grade', grade)
.eq('period', period)
.maybeSingle();
if (error) {
console.warn('[accuracy] fetch failed:', error.message);
return null;
}
return data;
}
async function upsertRow(supabase, row) {
const { error } = await supabase
.from('accuracy_tracking')
.upsert(row, { onConflict: 'sport,grade,period' });
if (error) console.warn('[accuracy] upsert failed:', error.message);
}
async function recordResolution(sport, grade, result) {
if (!sport || !grade || !result) return;
const supabase = getSupabaseServiceClient();
for (const period of PERIODS) {
const existing = await fetchRow(supabase, sport, grade, period) || {
sport, grade, period,
total_graded: 0, total_hit: 0, total_miss: 0, total_push: 0, total_void: 0,
hit_rate: null, baseline_hit_rate: null, baseline_locked: false,
};
existing.total_graded += 1;
if (result === 'hit') existing.total_hit += 1;
else if (result === 'miss') existing.total_miss += 1;
else if (result === 'push') existing.total_push += 1;
else if (result === 'void') existing.total_void += 1;
existing.hit_rate = computeHitRate(existing.total_hit, existing.total_miss);
if (
period === 'all_time'
&& !existing.baseline_locked
&& (existing.total_hit + existing.total_miss) >= BASELINE_LOCK_AT
) {
existing.baseline_hit_rate = existing.hit_rate;
existing.baseline_locked = true;
}
existing.last_updated = new Date().toISOString();
await upsertRow(supabase, existing);
}
}
async function getAccuracy(sport, grade, period = 'all_time') {
const supabase = getSupabaseServiceClient();
const row = await fetchRow(supabase, sport, grade, period);
if (!row) {
return {
sport, grade, period,
hit_rate: null,
baseline: null,
expected: EXPECTED_HIT_RATES[grade] ?? null,
total: 0,
delta: null,
locked: false,
};
}
const total = row.total_hit + row.total_miss;
const delta = row.baseline_hit_rate != null && row.hit_rate != null
? row.hit_rate - row.baseline_hit_rate
: null;
return {
sport, grade, period,
hit_rate: row.hit_rate,
baseline: row.baseline_hit_rate,
expected: EXPECTED_HIT_RATES[grade] ?? null,
total,
delta,
locked: !!row.baseline_locked,
};
}
async function getAllAccuracy(sport, period = 'all_time') {
const grades = Object.keys(EXPECTED_HIT_RATES);
const out = [];
for (const grade of grades) out.push(await getAccuracy(sport, grade, period));
return out;
}
async function isBaselineLocked(sport, grade) {
const supabase = getSupabaseServiceClient();
const row = await fetchRow(supabase, sport, grade, 'all_time');
return !!row?.baseline_locked;
}
async function getAccuracyDashboard() {
const supabase = getSupabaseServiceClient();
const { data, error } = await supabase
.from('accuracy_tracking')
.select('*')
.eq('period', 'all_time');
if (error) {
console.warn('[accuracy] dashboard query failed:', error.message);
return [];
}
return data || [];
}
module.exports = {
recordResolution,
getAccuracy,
getAllAccuracy,
isBaselineLocked,
getAccuracyDashboard,
EXPECTED_HIT_RATES,
BASELINE_LOCK_AT,
__internals: { computeHitRate, PERIODS },
};