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>
This commit is contained in:
+80
@@ -0,0 +1,80 @@
|
||||
# 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 2–5**: 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 ~3–4 (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.
|
||||
@@ -17,7 +17,11 @@
|
||||
* ticker:items — capped array of ticker events (newest first)
|
||||
*/
|
||||
|
||||
const SNAP_TTL = 6 * 3600; // 6h — a snapshot is valid until the next run
|
||||
// Session 60 (AUTONOMY P0) — 24h, NOT 6h. The overnight cron gap is 11 hours
|
||||
// (03:00 UTC → 14:00 UTC); with a 6h TTL the morning settle pass read an
|
||||
// EXPIRED snapshot and the accuracy loop silently settled nothing. The
|
||||
// snapshot must survive until the morning-after settle reads it.
|
||||
const SNAP_TTL = 24 * 3600;
|
||||
const TICKER_TTL = 24 * 3600;
|
||||
const TICKER_CAP = 50;
|
||||
const DELTA_NOISE = 0.5; // ignore movements smaller than this
|
||||
|
||||
Reference in New Issue
Block a user