Grade-fix validation script + finding doc (before-state, blast-radius SQL, plan)
scripts/validate-grade-fix.js checks the live MLB snapshot for the three degradation signatures (projection=0, edge=100 cluster, grade/conf disagreement) — run after the next 14:00 UTC regrade to fingerprint the fix. The finding doc now records root causes, fixes (commits 888d103/9fc4edf), the blast-radius SQL (box can't reach Supabase directly), and the shared-path note for NBA/WNBA. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env node
|
||||
// Post-fix re-grade validation (work-order item #4). Fetches the LIVE MLB
|
||||
// snapshot and checks the three degradation signatures are gone:
|
||||
// 1. projection == 0 count -> expect 0 (the nine vanish; those props refuse)
|
||||
// 2. edge_pct continuous, not the {20,60,100,140} degenerate cluster, no 100
|
||||
// 3. grade <-> confidence agreement -> expect 25/25 (letter == band(conf))
|
||||
// Run: node scripts/validate-grade-fix.js (needs outbound to api.vyndr.app)
|
||||
const https = require('https');
|
||||
const BANDS = require('../src/services/python/data/grade_thresholds.json').grade_scale;
|
||||
const four = (g) => { const s = String(g||'').toUpperCase(); return s === 'A+' ? 'A+' : (s[0]||null); };
|
||||
function bandOf(conf) { const p = conf/100; for (const [k,b] of Object.entries(BANDS)) if (p>=b.low && p<=b.high) return k; return null; }
|
||||
function get(url) { return new Promise((res,rej) => https.get(url,(r)=>{let d='';r.on('data',c=>d+=c);r.on('end',()=>res(JSON.parse(d)));}).on('error',rej)); }
|
||||
(async () => {
|
||||
const d = await get('https://api.vyndr.app/api/snapshot/mlb');
|
||||
const g = d.grades || [];
|
||||
const proj0 = g.filter(x => x.projection === 0 || x.projection == null).length;
|
||||
const edges = g.map(x => x.edge_pct).filter(v => v != null);
|
||||
const has100 = edges.includes(100);
|
||||
const distinctEdges = [...new Set(edges)].sort((a,b)=>a-b);
|
||||
let agree = 0;
|
||||
for (const x of g) { const b = bandOf(x.confidence); if (b && four(b) === four(x.grade)) agree++; }
|
||||
console.log('=== AFTER (post-fix) — live MLB snapshot ===');
|
||||
console.log('updated_at:', d.updated_at, '| grades:', g.length);
|
||||
console.log('1. projection==0/null:', proj0, proj0 === 0 ? 'PASS' : 'FAIL (expect 0)');
|
||||
console.log('2. edge_pct distinct:', distinctEdges.length, 'values; contains 100:', has100, (!has100 && distinctEdges.length > 4) ? 'PASS' : 'CHECK');
|
||||
console.log(' values:', distinctEdges.slice(0, 20));
|
||||
console.log('3. grade<->confidence agree:', agree + '/' + g.length, agree === g.length ? 'PASS' : 'FAIL');
|
||||
})().catch(e => { console.error('validation error:', e.message); process.exit(1); });
|
||||
Reference in New Issue
Block a user