Step 0 input check: read-only feature-coverage probe

Before wiring any layer into the grade, measure whether its inputs are
actually populated on real props. A layer wired onto sparse inputs does not
degrade gracefully by default -- Number(null) === 0 turns a missing
opportunity into 'zero opportunity', a fabricated input rather than an
absent one.

Reports population per feature, SPLIT BY stat_type, because a feature can
be 100% present for batters and 0% for pitchers and a pooled number would
hide exactly that. Also reports whether ab_per_game varies across a
player's own props -- a per-player constant can only move all of a
player's props together, which is a very different thing from a per-prop
opportunity signal.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
This commit is contained in:
Kev
2026-08-01 02:34:33 -04:00
parent ecdc644621
commit 3e78217678
2 changed files with 165 additions and 0 deletions
+23
View File
@@ -629,4 +629,27 @@ router.get('/diagnose-refusals', async (req, res) => {
}
});
/**
* GET /api/internal/feature-coverage (Connect-layers Step 0)
*
* READ-ONLY input check: before wiring any layer into the grade, measure
* whether its inputs are actually populated on real props. Writes nothing.
*
* ?sport=mlb&sample=60
*/
router.get('/feature-coverage', async (req, res) => {
try {
const { coverage } = require('../services/featureCoverage');
const out = await coverage({
sport: req.query.sport || 'mlb',
sample: parseInt(req.query.sample, 10) || undefined,
concurrency: parseInt(req.query.concurrency, 10) || undefined,
});
res.set('Cache-Control', 'no-store');
return res.json({ ok: true, ...out });
} catch (err) {
return res.status(500).json({ ok: false, error: err && err.message });
}
});
module.exports = router;