Files
builtbykev 4ddfb84232 Session A (night2): AUTONOMY.md + SNAP_TTL 6h→24h P0 fix
The overnight cron gap (03→14 UTC) is 11h; a 6h snapshot TTL meant the
morning settle pass read an expired snapshot and the accuracy loop
silently settled nothing. Ledger (Postgres) settle was immune.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 00:18:01 -04:00

4.4 KiB
Raw Permalink Blame History

AUTONOMY — "Kev touches nothing for 7 days, what happens"

Session 60 (night2), traced on d10bb4c + tonight's fixes. Every step cites its code. Verdict at the bottom.

The daily loop (all times ET / UTC)

10:00 AM ET (14:00 UTC) — cron slot 1 (snapshotScheduler.js HOURS_UTC = 14,19,22,1,3; armed by SNAPSHOT_CRON=1 in server.js):

  1. Settle pass runs FIRST (tick() order: settleAllOutcomes → settleAllLedgers → runAllSnapshots):
    • outcomeService.settleAllOutcomes — settles yesterday's snapshot grades vs real MLB game logs → outcomes:{sport}:log + accuracy:{sport} + accuracy:overall. P0 FIXED TONIGHT: SNAP_TTL was 6h but the overnight gap (03:00→14:00 UTC) is 11h — the snapshot EXPIRED before this pass and the accuracy loop settled nothing. Now 24h (snapshotService.js).
    • ledgerService.settleAllLedgers — settles Supabase ledger_entries (game_date < today ET): outcome + actual_value + CLV vs the captured closing line. Reads Postgres, immune to Redis TTLs. Idempotent (.is('outcome', null) guard) — re-runs are no-ops.
  2. Snapshot pass (snapshotService.runSnapshot per sport):
    • getOdds (PropLine free keys, odds-api backup) → date-pinned; a morning with no lines yet = honest skipped: no props (NOT retried — only thrown/null responses retry once).
    • grades → normalize/dedupe → archetype+team resolve (free statsapi) → snapshot:{sport}:latest + grades:{sport} (6h TTL — outlives the 5h max intra-day gap) → ticker events.
    • Ledger write: recordPipelineGrades upserts public rows (user_id NULL, ignoreDuplicates — re-runs never dupe or overwrite the original lock). captureClosing overwrites today's unsettled rows' closing_line/odds with current feed values.

3:00 PM / 6:00 PM / 9:00 PM / 11:00 PM ET — cron slots 25: same tick. Each run re-captures closing (the LAST write before a game starts is the real close — after start the prop leaves the feed, so it freezes), computes line deltas vs the previous snapshot (ticker MOVE), and upserts any newly posted props as new locked rows.

Overnight: games finish; nothing runs until 10 AM, when the settle pass closes yesterday's book. Every settled row gets outcome/actual/CLV exactly once.

Self-healing / watchdogs

  • Missed-cron watchdog (per-minute, isSnapshotOverdue) → ntfy alert (vyndr-pipeline-kev2026) once per missed slot. Snapshot success/empty/ failure also alert (opsNotify, never throws).
  • GET /api/internal/snapshot/status (internal key) → cron_armed, last snapshot, redis keys, overdue flag.
  • Schedule/streaks/hotlist read caches self-heal on miss (cache-aside ESPN, date-pinned since Session 57). Public snapshot/ledger reads are cache-only and can never drain quota.

What accumulates without touch (day 1 → day 7)

  • Day 1: first locked rows; MODEL tab "RECORD BUILDING · N pending".
  • Day 2 morning: first settles + CLV (closing captured day 1). AccuracyBadge leaves "LEARNING" at 8 settled; ledger aggregates render % at n≥20.
  • Day ~34 (MLB volume ~20-25 graded/day, all settleable): hit% + beat-close% go live on /ledger MODEL, landing ModelRecord, player strips.
  • Day 7: 30d-window aggregates, per-player records accruing. WNBA rows accumulate PENDING (honest) until Phase 4.5 (ESPN box-score settle, due ~Jul 24) — the one known credibility clock.

Dependencies that must stay true (the only touch-points)

  1. Coolify container running with SNAPSHOT_CRON=1, PropLine keys, SUPABASE_URL + service key, REDIS_URL. (One-time, already set.)
  2. Redis persistence is server-side config (Session 52) — snapshot keys vanishing on restart = Coolify Redis setting, not code. The LEDGER is Postgres and survives anything.
  3. ntfy channel monitored casually — alerts are informational; the loop needs no response.

Verdict

Zero-touch for 7 days: YES for the core record (grade→lock→close→ settle→aggregate, all scheduled in-process, idempotent, alert-covered) — after tonight's SNAP_TTL fix, which was the one broken link (morning settles silently skipped). Known honest gaps: WNBA settles pending until 4.5; streaks/hot-list data production was EXTERNAL (tank01-prefetch via n8n/cron, possibly unarmed) — Session B moves log production into the snapshot pipeline so the aggregator feeds itself.