Codex commited on
Commit ·
a0f98a7
1
Parent(s): cf14c48
Add Circa post-parse validation
Browse files- src/market-scanner.js +39 -1
- test/market-scanner.test.js +11 -0
src/market-scanner.js
CHANGED
|
@@ -770,7 +770,45 @@ export function parseCircaOcrText(text) {
|
|
| 770 |
entries.push(entry);
|
| 771 |
}
|
| 772 |
|
| 773 |
-
return dedupeBy(entries, (entry) => `${entry.marketKey}|${entry.book}`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 774 |
}
|
| 775 |
|
| 776 |
function dedupeBy(values, getKey) {
|
|
|
|
| 770 |
entries.push(entry);
|
| 771 |
}
|
| 772 |
|
| 773 |
+
return dedupeBy(entries.filter(isLikelyValidCircaEntry), (entry) => `${entry.marketKey}|${entry.book}`);
|
| 774 |
+
}
|
| 775 |
+
|
| 776 |
+
function isLikelyValidCircaEntry(entry) {
|
| 777 |
+
const playerName = normalizeWhitespace(entry.playerName);
|
| 778 |
+
if (!playerName || playerName.length < 3 || /\d/.test(playerName)) {
|
| 779 |
+
return false;
|
| 780 |
+
}
|
| 781 |
+
|
| 782 |
+
const words = playerName.split(/\s+/).filter(Boolean);
|
| 783 |
+
if (words.length < 2 || words.length > 4) {
|
| 784 |
+
return false;
|
| 785 |
+
}
|
| 786 |
+
|
| 787 |
+
if (words.some((word) => word.length < 2)) {
|
| 788 |
+
return false;
|
| 789 |
+
}
|
| 790 |
+
|
| 791 |
+
const oddsValue = Number(entry.oddsInput);
|
| 792 |
+
if (!Number.isFinite(oddsValue)) {
|
| 793 |
+
return false;
|
| 794 |
+
}
|
| 795 |
+
|
| 796 |
+
if (entry.marketType === 'home_runs') {
|
| 797 |
+
if (entry.side === 'yes' && (oddsValue < 100 || oddsValue > 2000)) {
|
| 798 |
+
return false;
|
| 799 |
+
}
|
| 800 |
+
if (entry.side === 'no' && (oddsValue > -100 || oddsValue < -5000)) {
|
| 801 |
+
return false;
|
| 802 |
+
}
|
| 803 |
+
}
|
| 804 |
+
|
| 805 |
+
if (entry.lineValue !== null && entry.lineValue !== undefined) {
|
| 806 |
+
if (entry.lineValue < 0 || entry.lineValue > 20) {
|
| 807 |
+
return false;
|
| 808 |
+
}
|
| 809 |
+
}
|
| 810 |
+
|
| 811 |
+
return true;
|
| 812 |
}
|
| 813 |
|
| 814 |
function dedupeBy(values, getKey) {
|
test/market-scanner.test.js
CHANGED
|
@@ -93,6 +93,17 @@ test('recovers multiple packed home run rows from one OCR line', () => {
|
|
| 93 |
assert.ok(entries.some((entry) => entry.playerName === 'GUNNAR HENDERSON' && entry.oddsInput === '+525'));
|
| 94 |
});
|
| 95 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
test('ranks discrepancy, width, and circa alerts', () => {
|
| 97 |
const entries = [
|
| 98 |
{
|
|
|
|
| 93 |
assert.ok(entries.some((entry) => entry.playerName === 'GUNNAR HENDERSON' && entry.oddsInput === '+525'));
|
| 94 |
});
|
| 95 |
|
| 96 |
+
test('filters obviously invalid circa player-name rows', () => {
|
| 97 |
+
const entries = parseCircaOcrText([
|
| 98 |
+
'WILL [PLAYER] HIT A HOME RUN?',
|
| 99 |
+
'AARON JUDGE (NYY) 83681 +235 83682 -280',
|
| 100 |
+
'AS667 NATIONALS A YANKEES 83681 +235 83682 -280',
|
| 101 |
+
].join('\n'));
|
| 102 |
+
|
| 103 |
+
assert.ok(entries.some((entry) => entry.playerName === 'AARON JUDGE'));
|
| 104 |
+
assert.ok(!entries.some((entry) => /NATIONALS A YANKEES/.test(entry.playerName)));
|
| 105 |
+
});
|
| 106 |
+
|
| 107 |
test('ranks discrepancy, width, and circa alerts', () => {
|
| 108 |
const entries = [
|
| 109 |
{
|