Session 59: Addendum + work-order 1.6 + Phase 2 + Phase 3 (2352 tests)

Overnight sprint for the Saturday 10 AM ET deploy gate — day one of the
public ledger record locks against freshly posted lines.

Task A — ledger team/opponent (migration 020, applied at 0 rows):
  populated in both write paths from the real feed; opponent only when the
  player's team matches a game participant (never guessed). Roadmap: Phase
  4.5 WNBA ESPN-boxscore settlement (due ~Jul 24) + Phase 5 per-tier
  calibration logged.

Task B — work-order 1.6 CLOSED (canonical player keys):
  - searchPlayer resolves via nameKey; the old matcher deleted accents
    ("Sanchez" with acute -> "snchez") and substring-guessed onto the WRONG
    player (the mismatched last-10 bug). Ambiguous -> null, never guess.
  - Slate JOIN INVARIANT: a graded prop whose player's real team isn't in
    the game is dropped (TB player can't render under MIL@PIT) — locked by
    tests that fail the suite on regression.
  - grades:{sport} TTL 2h -> 6h (expired between 5h cron gaps — the real
    cause of /team "No active props" for slate players).

Task C — Phase 2 slate UX: tabs are THE filter (URL ?sport=, deep-linkable,
  duplicate legacy tablist removed); cards cap at 6 graded props sorted
  A+->F with ALL N READS in-place expander; waiting states show the real
  next pipeline run ("Grades post ~6:00 PM ET").

Task D — Phase 3 mobile P0: root cause of vanished 390px nav was HIDE_ON
  including '/' (landing had zero navigation) — fixed; html/body overflow-x
  contained; GAME LINES collapses to best-line summary + "N BOOKS" expander
  below 640px; venue drops before time/pitchers ever truncate.

Live verification: raw ESPN today STILL returns the Jun 13 NYK@SA Finals
game without a date pin; the pinned fetch returns 0 games, 0 off-date.

Backend 2327 -> 2352 tests (202 suites), web build exit 0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kev
2026-07-10 22:24:47 -04:00
parent c96e74c54b
commit d10bb4cce2
20 changed files with 648 additions and 80 deletions
+48 -4
View File
@@ -4,10 +4,54 @@
2026-07-10
## Current Phase
SHIP BUILD v58.0 — Phase 1 "Truth Infrastructure": ledger_entries live in
Supabase (migration applied + RLS verified), both write paths wired, nightly
settlement + CLV, /ledger MY READS | MODEL tabs, honest scan refusals.
Next: work-order Phase 2 (slate UX) + Phase 3 (mobile), then Phase 2.5.
SHIP BUILD v59.0 — Overnight session: ledger team/opponent addendum,
work-order 1.6 closed (canonical player keys + slate join invariant),
Phase 2 slate UX, Phase 3 mobile P0. DEPLOY GATE: Coolify by Sat 10 AM ET;
first snapshot locks against freshly posted lines (manual internal trigger).
## Session 59 (2026-07-10 overnight) — SHIPPED ✅ ADDENDUM + 1.6 + PHASE 2 + PHASE 3
Backend 2327 → **2352 tests** (+25), 202 suites. Web build clean (exit 0).
Migration 020 (team/opponent) APPLIED while ledger_entries was at 0 rows —
zero backfill needed; VYNDR-on-team unblocked.
- **Task A** — `ledger_entries.team/opponent` populated in both write paths
(pipeline: stats-resolve team + prop's other side via nickname match,
NEVER guessed; scan: snapshot-grade team, opponent null). Roadmap: Phase
4.5 (WNBA ESPN box-score settlement — DUE ~Jul 24) + Phase 5 calibration-
by-grade-tier logged.
- **Task B (work-order 1.6 CLOSED)** — `mlbStatsAdapter.searchPlayer` now
resolves via canonical `nameKey` (the old matcher DELETED accents:
"Sánchez"→"snchez"≠"sanchez", then substring-guessed → wrong player's
last-10). Fallback = UNIQUE last-name+first-initial or null.
`buildPlayerStripsFromProps` gained the JOIN INVARIANT: a graded prop
whose player's real team isn't a game participant is DROPPED (TB player
can't render under MIL@PIT — suite fails if it regresses). Snapshot
grades now carry `team`. Root cause of /team "No active props":
grades:{sport} TTL (2h) < cron gap (5h) → now SNAP_TTL (6h).
- **Task C (Phase 2)** — 2.1 sport tabs are THE filter, URL-driven
(?sport=, deep-linkable); the dashboard's duplicate legacy tablist is
GONE (legacy sections subscribe via onTabChange). 2.2 cards cap at 6
graded props sorted A+→F with "ALL N READS →" expanding in place.
2.3 waiting states show the REAL next pipeline run ("Grades post
~6:00 PM ET" via lib/pipelineSchedule — mirrors SNAPSHOT_HOURS_UTC;
update BOTH if the cron changes). 2.4 = TTL fix + join fix (verify on
the live Yankees page post-deploy).
- **Task D (Phase 3)** — ROOT CAUSE of vanished mobile nav: HIDE_ON
included '/' — the landing had NO nav at 390px (desktop links hidden,
hamburger retired S37, tab bar suppressed). '/' removed. 3.2: html/body
overflow-x hidden <768; GAME LINES collapses to a best-line summary +
"N BOOKS ⌄" expander <640; venue (.gc-venue) drops first on phones.
- **Live verification:** raw ESPN (no date pin) STILL returns the Jun 13
NYK@SA Finals game today; the pinned fetch returns 0 games, 0 off-date.
### Morning deploy runbook (Sat, before ~10 AM ET)
1. Push already sent to gitea (Coolify betonblk) — confirm deploy finished.
2. `GET /api/internal/snapshot/status` (x-internal-key) → cron_armed true.
3. When the day's lines post: `POST /api/internal/snapshot/all`
(x-internal-key) → first public ledger rows lock against fresh lines.
4. Verify: `SELECT count(*), count(*) FILTER (WHERE team IS NOT NULL) FROM
ledger_entries WHERE user_id IS NULL;` + one sample row.
## Session 58 (2026-07-10) — SHIPPED ✅ PHASE 1: TRUTH INFRASTRUCTURE