feat: Feature 2.2 — Line Movement + Cascade Detection
Line movement system: - Baseline capture on first odds fetch of the day - Movement detection >= 0.5 points with direction (up/down) - Sharp money heuristic (sharp_action/public_action/unknown) - GET /api/movements with player, stat_type, min_movement filters - Movements included in GET /api/odds/nba live responses Cascade detection system: - Scratch detection: player props disappear from 2+ books - Affected user lookup via scan_sessions + picks - Parlay re-grade without scratched legs - cascade_alerts created for affected users - GET /api/alerts (Analyst/Desk only), PATCH /api/alerts/:id/read Zero extra Odds API credits — all detection piggybacks on existing fetches. Migration 002: line_baselines, line_movements, cascade_alerts tables. 30 new tests, 188 total (161 Node.js + 27 Python), all passing. Phase 2 Core Product COMPLETE. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const sql = fs.readFileSync(
|
||||
path.join(__dirname, '../../supabase/migrations/002_line_movement.sql'),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
describe('Migration 002 — Line Movement', () => {
|
||||
test('creates line_baselines table', () => {
|
||||
expect(sql).toContain('CREATE TABLE public.line_baselines');
|
||||
});
|
||||
|
||||
test('creates line_movements table', () => {
|
||||
expect(sql).toContain('CREATE TABLE public.line_movements');
|
||||
});
|
||||
|
||||
test('creates cascade_alerts table', () => {
|
||||
expect(sql).toContain('CREATE TABLE public.cascade_alerts');
|
||||
});
|
||||
|
||||
test('line_movements has direction constraint', () => {
|
||||
expect(sql).toMatch(/direction.*CHECK.*\(direction IN \('up',\s*'down'\)\)/);
|
||||
});
|
||||
|
||||
test('cascade_alerts has alert_type constraint', () => {
|
||||
expect(sql).toMatch(/alert_type.*CHECK.*\(alert_type IN/);
|
||||
});
|
||||
|
||||
test('cascade_alerts has RLS enabled', () => {
|
||||
expect(sql).toContain('ALTER TABLE public.cascade_alerts ENABLE ROW LEVEL SECURITY');
|
||||
});
|
||||
|
||||
test('cascade_alerts has select and update policies', () => {
|
||||
expect(sql).toContain('CREATE POLICY "alerts_select_own"');
|
||||
expect(sql).toContain('CREATE POLICY "alerts_update_own"');
|
||||
});
|
||||
|
||||
test('unique index on baselines prevents duplicates', () => {
|
||||
expect(sql).toContain('CREATE UNIQUE INDEX idx_baseline_unique');
|
||||
});
|
||||
|
||||
test('cleanup function exists', () => {
|
||||
expect(sql).toContain('CREATE OR REPLACE FUNCTION public.cleanup_old_baselines');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user