dCLV close leg: read priced captures only (the unfixed twin)
computeDirectionalForRow selected the latest closing_captures row with no missed_reason filter, while its sibling attachClosingProb has had one since the CLV instrument repair. closing_captures records a refusal for every prop x book x side on every cycle after first pitch, so a refusal always carries a later captured_at than the last real price - latest-first returned a refusal on 26,448 of 26,448 identity groups, and computeDirectionalClv refuses on a missedReason. That is why dclv_state has been 'unknown' on 100% of rows since Session 64. Measured on 600 real settled rows: 100% unknown becomes flat 45.8%, negative 23.0%, positive 22.8%, unknown 8.3%. ClvBadge will render MOVED TOWARD US 114 and MOVED AWAY 117 per 600 - near-symmetric, which is the honest shape. Existing rows do not recompute (first-computation-wins). The re-stamp is described in BUILD-STATE, not run. The grade is untouched. No rows deleted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -605,10 +605,25 @@ async function computeDirectionalForRow(sb, sport, row, deps = {}) {
|
||||
.eq('sport', sport).eq('player_key', row.player_key).eq('stat', row.stat)
|
||||
.eq('side', row.side).eq('game_date', row.game_date)
|
||||
.order('captured_at', { ascending: true }).limit(1),
|
||||
// ── FIX B1 — READ ONLY PRICED CAPTURES ──────────────────────────
|
||||
// This select had no `missed_reason` filter while its sibling
|
||||
// `attachClosingProb` (above) has had one since the CLV instrument repair.
|
||||
// `closing_captures` records a refusal for every prop x book x side on
|
||||
// every ~20-minute cycle AFTER first pitch, so those rows always carry a
|
||||
// LATER `captured_at` than the last real price — and `latest-first`
|
||||
// therefore returned a refusal on 100% of identity groups (measured:
|
||||
// 26,448 of 26,448 over five days). `computeDirectionalClv` refuses on a
|
||||
// `missedReason`, which is why `dclv_state` has been 'unknown' on every
|
||||
// row since Session 64.
|
||||
//
|
||||
// The filter belongs BEFORE the limit: latest of the PRICED rows, not
|
||||
// "the latest row, hopefully priced".
|
||||
sb.from('closing_captures')
|
||||
.select('over_odds, under_odds, missed_reason, captured_at')
|
||||
.eq('sport', sport).eq('player_key', row.player_key).eq('stat', row.stat)
|
||||
.eq('side', row.side).eq('game_date', row.game_date)
|
||||
.is('missed_reason', null)
|
||||
.not('over_odds', 'is', null).not('under_odds', 'is', null)
|
||||
.order('captured_at', { ascending: false }).limit(1),
|
||||
]);
|
||||
const lock = snaps && snaps[0];
|
||||
@@ -1085,5 +1100,9 @@ module.exports = {
|
||||
rowsFromSnapshot, computeClv, clvResultOf, indexProps, gameIdFor,
|
||||
dateET, sideOf, oddsForSide, isConfigured, CONFLICT,
|
||||
teamOpponentFor, teamsMatch, clvBucketIndex, CLV_BUCKETS,
|
||||
// B1 — exported so the close leg is directly testable. It was untestable,
|
||||
// and that is why the missing missed_reason filter survived while its
|
||||
// sibling was fixed a few lines above it.
|
||||
computeDirectionalForRow,
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user