Commit Graph

61 Commits

Author SHA1 Message Date
builtbykev 72a14dc4cd Build /api/props/top-graded server selector: rank with p_win, serve without it
New READ endpoint. No grade, ledger row, lock_line, or scoring write. Push
scoring untouched.

REVIEW ZERO CORRECTED THE PREMISE: the handler NEVER EXISTED in any commit
(searched git rev-list --all for a /top-graded definition in src/ — zero hits).
Not "removed" — the three axios callers (cheatsheetGenerator, gradeOfTheDay,
widget) and the Next proxy were written against a phantom endpoint, so those
three content generators have silently received [] for their entire life.
Contract recovered from the four consumers, not guessed: {props:[...]},
?sport=UPPERCASE (absent = all sports, which gradeOfTheDay relies on) + ?limit,
rows carrying player/stat/line/direction/sport/grade/confidence? plus the
player_name/stat_type aliases and game_id.

POPULATED-PATH RISK FOUND: the board's populated branch had never run in prod,
and dashboard/page.tsx:463 calls g.stat.replace(/_/g,' ') UNGUARDED (g.player
also feeds the row key, /scan URL and heading; sport must be UPPERCASE for
SportPill). toRow requires non-empty string player+stat and a finite line,
uppercases sport, and DROPS unrenderable rows — a shorter board beats a broken
one.

THE LEAK BOUNDARY (why this is server-side): the browser cannot rank on p_win
for all tiers because stripModelPrice deliberately withholds it from unentitled
tiers. Order of operations is
  read cache -> RANK with p_win (every tier) -> map rows incl. model fields
    -> stripModelPrice(rows, tier) -> serialize
so a free caller receives the paid RANKING without the paid VALUES. Tier comes
from resolveTierFromRequest, which FAILS CLOSED to 'free'. Cache-Control is
private under a bearer token, public otherwise (the /api/snapshot precedent).

ONE SHARED DEFINITION, no drift: new src/utils/gradeRanking.js
(takeablePWin/descNullsLast/rankGrades). heroPropService now imports
takeablePWin instead of its inline copy (behaviour unchanged — it was that
logic verbatim); the selector imports rankGrades; web/src/lib/slateAdapter
keeps its mirror (the browser cannot import src/, S25) and a test cross-checks
the two on identical fixtures (playerName.js precedent). Board is grade-first
("top GRADES"), hero is p_win-first ("top read") — they differ BY DESIGN and
agree within the leading tier.

HONEST LIMIT: the Next proxy (cachedBackendJson) sends no Authorization header
and caches under a shared key, so via the dashboard every viewer gets the
free-tier payload — correct order, no paid values. That is the SAFE behaviour;
forwarding auth into a shared cache is exactly how a paid payload leaks to
anonymous viewers. Per-tier delivery through the proxy needs a tier-keyed cache
and is not done here.

Verified on real prod snapshot data (anonymous path): MLB 8 props, WNBA 10,
0 paid-field leaks, render-contract safe on every row, sport uppercase.

Floor: 311 suites / 3882 tests green (18 new — leak test uses POPULATED p_win,
not today's nulls: entitled gets p_win and it drove the order, unentitled gets
a byte-identical order with all five MODEL_FIELDS absent and no trace in
JSON.stringify, while book/fair market facts survive). Web build exit 0.
Dashboard visual is auth-gated -> tagged for the Chrome audit, not faked.

Held: edge_pct rescale/retirement (Order B); board columns/contract unchanged;
tier-keyed proxy caching.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
2026-07-29 22:05:30 -04:00
builtbykev 69feab4d25 docs: grade-board sort fingerprinted (deploy boundary captured; ladder induced both directions)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
2026-07-29 21:18:25 -04:00
builtbykev b85b351993 Grade-board sort: signed signal, takeable-gated p_win, missing sorts LAST
Display ORDERING only. No grade, ledger row, lock_line, scoring, or edge_pct
scale/display change. Push scoring untouched.

Two defects removed from selectTopGrades (wrong at ANY scale, independent of
edge_pct's separate retirement):
  1. edge: Math.abs(numOr(g.edge, -Infinity)) — abs() on an already-
     direction-signed value ranked the model's strongest DISAGREEMENTS level
     with its strongest agreements (177 public ledger rows carry a negative
     edge; positive = the model AGREES with the graded side).
  2. Math.abs(-Infinity) === Infinity, so a row with NO edge sorted FIRST —
     absent data presented as the top pick (the Number(null) class).

New key: grade -> confidence -> takeable-gated p_win (nulls LAST) -> SIGNED
edge (nulls LAST) -> input order. Scales are never mixed in one comparator.
Takeable band = web valueState.isTakeable, asserted byte-equal to the hero's
config/valueEngine.isTakeable (-160..+200) incl. strict-null.

Alt-line ladder (analyzeViaEngine1:506) no longer sorts by edge_pct: ordered
highest-p_win-first derived analytically at zero added compute — P(stat >= k)
is monotone non-increasing in k, so p_win-desc is line-ASC for an over and
line-DESC for an under. base stays marked; no consumer depends on
alt_lines[0]; deskShowcaseService.rungsOf already re-sorted by line.

THREE PREMISE BREAKS found report-first, before code:
  - /api/props/top-graded 404s in prod (absent from src/) so the dashboard
    board renders receipts/empty — the edge sort orders nothing there today.
    The prior order's "97.3% of rows tie" was a LEDGER measurement wrongly
    extrapolated to that board. Fix is correct-in-itself and lands when the
    feed is restored.
  - p_win cannot be a client-side key for all tiers: snapshotGating strips it
    for unentitled tiers ("shipping p_win is shipping the model price").
    Verified live: prod /api/snapshot carries p_win on 0/8 MLB, 0/25 WNBA.
  - Ladder rungs carry no per-rung price, so the takeable gate is inapplicable.

Verified on real data, both sports, both paths: unentitled — WNBA (n=25)
ordering CHANGED, MLB (n=8) unchanged, signed edge non-increasing in every
(grade,confidence) tie group (20 pairs, 0 violations); entitled — 40 real
ledger rows with p_win+locked_odds, p_win-descending, untakeable chalk NOT
promoted (Trea Turner .757 @-275 does not beat Rhyne Howard .745 @-120)
(36 pairs, 0 violations).

Hero consistency, stated honestly: same signal + same gate, different
precedence BY CONTRACT (board = grade-tier-first "top GRADES"; hero =
p_win-first "top read"). Identical within the leading tier (verified); across
tiers the board may lead with an A the hero doesn't pick. Not a contradiction.

Floor: 310 suites / 3864 tests green, web build exit 0. Dashboard + Desk
visuals are auth/feed-gated -> tagged for the Chrome audit, no visual faked.

Held: edge_pct rescale/display retirement (Order B); building the missing
/api/props/top-graded selector; exposing p_win to unentitled tiers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
2026-07-29 21:13:51 -04:00
builtbykev 9b5235cf99 docs: hero ranking fix verified (new code serving — max-p_win takeable, chalk excluded)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VsztNChZ7vEvSR61AuMhD1
2026-07-29 04:53:15 -04:00
builtbykev e7ec501054 docs: book-comparison verify note (live-card screenshot auth-blocked; data feed + tests verify)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VsztNChZ7vEvSR61AuMhD1
2026-07-29 04:13:47 -04:00
builtbykev 36014c7c30 docs: Book Comparison wired to the prop card (matrix row 18 DONE, 16/26)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VsztNChZ7vEvSR61AuMhD1
2026-07-29 04:10:58 -04:00
builtbykev 3a05447f77 docs: lock-line persistence unblocks the staleness audit (migration 033, lock_lines)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VsztNChZ7vEvSR61AuMhD1
2026-07-29 02:49:02 -04:00
builtbykev 37261260d1 report: over-side skew audit — champion over-CLV SURVIVES baseline (promising, not confirmed)
Read-only. Takeable MLB overs n=62. Mechanical baseline (no-edge) CLV +1.51pt
(n=20); high-edge +8.64pt (n=37); difference +7.14pt = real edge. Champion
p_win->CLV partial r=0.375 (SIG p~0.003) survives price control. Skew one-sided
(unders -7, over baseline +1.5). De-vig clean (same-book pairing, analyzeViaEngine1:539);
close well-defined (DK/MGM r=0.92). Greenlights building the takeable-edge grade
ON THE CHAMPION, not proj-v1.1. Flagged promising-not-confirmed: thin n, lock-time
multi-book staleness check BLOCKED (not retained), pinnacle ref n=8. No fix, no
promotion — diagnosis only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VsztNChZ7vEvSR61AuMhD1
2026-07-29 02:28:21 -04:00
builtbykev 59b77cdef2 report: proj-v1.1 takeable-edge proof — NOT PROVEN (n=45 MLB overs)
Read-only proof. N-gate passed (overlap 45). proj-v1.1 edge-CLV partial
correlation controlling for price = 0.245 (n.s.); ~half the raw 0.455 is the
shared -fair_prob_lock term (mechanical). Champion out-predicts proj on the
same rows (champ partial-CLV 0.380 sig; champ-edge->hit 0.25 vs 0.12). Unders
contaminated (CLV -9.3); WNBA proj-v1.1 doesn't run. Promotion HELD; the
under-audit is moot since proj loses to the champion first.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VsztNChZ7vEvSR61AuMhD1
2026-07-29 00:47:56 -04:00
builtbykev b8ee216c62 docs: CLV instrument repair + the straight finding (unders lag the close)
closing_prob 59 -> 406 (MLB 248, WNBA 158). Root cause was attachClosingProb's
truncated read + write-once market_unavailable, not capture or the join. CLV
measured: MLB unders lag the close (mean -9.1 prob-pts, 74% lose), MLB overs
+2.0, WNBA flat -> the +4.57% MLB-C and over/under asymmetry are substantially
stale-line artifacts. Unblocks the proj-v1.1 proof order.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VsztNChZ7vEvSR61AuMhD1
2026-07-28 19:04:50 -04:00
builtbykev afb56b144b NexaPay purge: VYNDR is Stripe-only — remove all NexaPay traces
NexaPay was cross-project contamination (from another venture) — never a real
VYNDR payment path. Purged; Stripe path untouched.

Removed:
- web/src/services/nexapay.ts (createPaymentLink/getTransaction/HMAC verify)
- web/src/app/api/webhook/nexapay/route.ts (the only importer; Next-registered,
  reachable — now gone)
- NexaPay comments in email.ts + checkout/route.ts
- Active NexaPay entries in docs/SYSTEM-MANIFEST.md (route list, NEXAPAY_* env
  table, service row) + stale claim in wiring-data-train.md
- sw.js precache entry for the deleted webhook chunk

Verified: ZERO NexaPay in code (web/src, src, tests). Full suite 3833 green
(count unchanged — nothing depended on it, confirming it was dead). Web build
exit 0. sw.js parses clean. Stripe checkout untouched (Next→Express→Stripe).

FLAGGED FOR KEV (a repo delete cannot close these):
- Coolify env: remove NEXAPAY_API_KEY / NEXAPAY_WEBHOOK_SECRET / NEXAPAY_API_URL
- Revoke the NexaPay API key + webhook secret at NexaPay's dashboard; de-register
  the webhook if an account was ever configured
- DB column user_profiles.nexapay_customer_id is orphaned (no reader/writer) —
  drop via a follow-up migration (migration 011 left as history)

Cross-project check: ZERO Noctem-Supabase refs; VYNDR references only its own
Supabase (zmdnczhtdxcddsxzttub). NexaPay was the sole contamination found.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VsztNChZ7vEvSR61AuMhD1
2026-07-27 16:51:59 -04:00
builtbykev 3592aba8d5 docs: log honesty pass in completion matrix + STATE (rows 19/20/24 HONEST fixed)
Records the six live fabrications removed/hidden, keeps media/newsletter/WIRE on
the board as real work, logs the news/line-movement signal as a future model
input, and logs the known honesty gaps (hit-rate-without-ROI, CLV starved).
Honest state: "no KNOWN live fabrications," not "provably none."

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VsztNChZ7vEvSR61AuMhD1
2026-07-27 06:07:21 -04:00
builtbykev be6b4a2849 inventory: VYNDR-COMPLETION-MATRIX (5-part DONE map of every surface + model)
Read-only inventory order — no code built/wired/fixed/deployed. Maps every
user-facing surface and model component against DESIGNED·BUILT·WIRED·LIVE·HONEST,
re-derived from repo b0a51c8 + prod + design bundle (not STATE.md narrative).
15/26 surfaces fully done. Names the graveyard (BookComparison, ShareCard,
proj_ladder, arch-v1/contact-v1 ledger-only, /intelligence orphan) and the live
honesty gaps (/compare hardcoded, FAQ NexaPay/Brier, MobileEdgeBoard placeholder,
EV fields NULL on served grades). STATE.md now points to the matrix as canonical.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VsztNChZ7vEvSR61AuMhD1
2026-07-27 05:12:59 -04:00
builtbykev e81c9b8c51 Book Comparison Phase 1-3(backend): fenced per-book store + honest gated crown
Per-book prices existed only transiently (odds cache, ~1h, raw names, grade-path
input); every grade-path persistence point collapses to one book. The
/api/books feature was built+mounted but non-functional (fed FLAT rows to a
GROUPED comparator -> always empty).

Phase 1: bookPriceStore captures per-book prices from `props` BEFORE dedupeProps,
keyed nameKey|stat, into bookprices:{sport} (SNAP_TTL) in snapshotService. Fenced:
reads props, writes its own key, read by nothing on the grade path. Grade proven
byte-identical (test + no-grade-path-reference grep test).

Phase 2: scripts/measure-book-spread.js reports same-line best-vs-worst spread
(cents + implied-prob pts), per sport, never pooled. Pre-registered crown
threshold: median >=8c OR >=2pp. Runs post-deploy on real data.

Phase 3 (backend): compareProp is honest-absent (single-book/flat -> no crown)
and the crown is gated (BOOK_CROWN_ENABLED, default OFF until Phase 2 clears).
/api/books repointed to the snapshot-locked store (fallback odds cache),
nameKey-matched; `source` field is the deploy fingerprint.

HELD unchanged: dedupeProps, snapshot dedup, selector, grade, champion,
challengers, ranking, edge_pct/ev_pct. UI routing of BookComparison + crown
treatment deferred to post-measurement (gated on Phase 2). Full suite 3834 green,
web build exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VsztNChZ7vEvSR61AuMhD1
2026-07-27 00:45:01 -04:00
builtbykev 9a91837f63 STATE: Session 80 — S7 nudge freshness completed; premise corrected report-first
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
2026-07-22 12:20:49 -04:00
builtbykev 33d72e38f9 STATE: Session 79 — read-card no-market empty state + priced-line surfacer, live
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
2026-07-22 11:24:39 -04:00
builtbykev 535a7b70ea STATE: Session 77 — dormant adjusters wired; env non-null proven, ledger row pending
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
2026-07-21 21:41:21 -04:00
builtbykev 2adf192d98 STATE: Session 76 — platoon regressed; plumbing gap now four orders old
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
2026-07-21 01:58:04 -04:00
builtbykev 9086951852 STATE: Session 75 — weather modulation composed onto park; venue gap still open
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
2026-07-21 01:43:41 -04:00
builtbykev 5b4af67d93 STATE: Session 74 — public park base pluggable, game-context capture live
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
2026-07-21 01:23:28 -04:00
builtbykev 63e4bce858 STATE: Session 73 — park factors derived + composable; pipeline gap documented
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
2026-07-21 01:06:49 -04:00
builtbykev beac1816d2 STATE: Session 72 — Tier-1 live, Tier-2 harness forward-accrual (no historical OOS)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
2026-07-21 00:30:46 -04:00
builtbykev 56fee267c9 STATE: Session 71 — challenger deployed; verification gap documented honestly
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
2026-07-21 00:04:24 -04:00
builtbykev 80f7100fc3 STATE: Session 70 — measurement instrument wired; the baseline accrues forward
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
2026-07-20 23:12:27 -04:00
builtbykev 063e9fb3f7 STATE: Session 69 — multi-axis archetypes live, FLEX fabrication deleted
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
2026-07-20 22:40:26 -04:00
builtbykev 27aabd078f STATE: Session 68 — Layer 1 mechanism data live (1,354 rows, 100% join)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
2026-07-20 21:55:30 -04:00
builtbykev 0264486bf9 STATE: Session 67 — price layer gated at two doors, read card wired
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
2026-07-20 19:59:33 -04:00
builtbykev 16697a4b90 STATE: Session 66 — price-layer tokens + the triplet, with induction proof
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
2026-07-20 18:33:02 -04:00
builtbykev 38ee83d0be STATE: Session 65 — CLV un-claim + FORM un-fabricate, with live fingerprint
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
2026-07-20 17:09:01 -04:00
builtbykev f5156dd16d Un-claim CLV on the public profile; un-fabricate player-page FORM
Two Truth-Law fixes found by auditing the product logged-out.

FIX 1 — /u/[handle] claimed a "CLV-verified record" with "closing-line
value included" while ZERO closing-line value renders there. Verified
live: GET /api/profiles/vyndr returns beat_close_pct null (gated behind
CLV_CAPTURE_RELIABLE, unset while C4 is open). Eight instances found —
two of them (the OG + portrait "CLV-VERIFIED RECORD · 30D" eyebrows)
only by the post-removal residual sweep; two more printed the claim in
exactly the no-record branch.

Copy now describes what the page shows. The gated CLV-VERIFIED badge and
the BEAT CLOSE figure are removed from the public profile, OG card and
portrait card. DISPLAY ONLY: beat_close_pct, clvCaptureReliable() and
the whole CLV data path are untouched, and the earned directional badge
stays Analyst+Desk. The claim returns when CLV genuinely renders here.

Also fixes the doubled "· VYNDR · VYNDR" title (layout's '%s · VYNDR'
template already supplies the suffix); verified on composed output by
serving the build and reading the real HTML, not on source.

FIX 2 — the player page's FORM was `70 + 4 × (count of tonight's graded
props)`. Nothing on the HTTP path ever sets stats.form, so that fallback
WAS the live number: Josh Bell's "74" is 70 + 4×1 prop, confirmed
against his live payload. MATCHUP was gradeFromForm(that number), with a
hardcoded 'B' on the no-archetype branch — both fabricated letters with
no opponent input on the path. Systemic: buildIntel is the unconditional
path for every player and sport.

FORM and MATCHUP now render "—" (kind 'plain', so no bar width or colour
is computed off a null). gradeFromForm is deleted and the prop count is
no longer passed into buildIntel. computeFormScore's hardcoded 75 now
returns undefined. Induced across MLB/NBA/WNBA: all render cleanly, and
real values (USAGE 3.6 AB/G, REST B2B) still render.

Neither form value feeds the grade — engine1 reads raw l5_avg/l20_avg
against the line and never a form key; buildIntelFields decorates the
already-graded object. Grade inputs are byte-identical.

Held (needs a per-sport headline-stat design call): a real player-level
form metric + label disambiguation.

Tests 3491 passed / 289 suites, web build exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
2026-07-20 17:05:04 -04:00
builtbykev b1ed675500 STATE: MLB opp_rank_stat live — consumption proven, coverage 8/14, factor inert this slate 2026-07-20 12:53:39 -04:00
builtbykev 2321267346 STATE: harness armed + closing capture started; reverted my own non-close writes 2026-07-20 12:09:12 -04:00
builtbykev f73fb64a43 STATE: heal executed — 64 re-voided, 25+200 quarantined, scopes separated 2026-07-20 05:45:27 -04:00
builtbykev b76e35f575 STATE: grading date binding fixed + blast radius quantified 2026-07-20 03:52:34 -04:00
builtbykev 8e17de4010 STATE: game_date root fixed, 64 voids reverted, grading blast radius flagged 2026-07-20 03:27:42 -04:00
builtbykev e46c88e364 STATE: retention clock proven ticking via induced cron entrypoint 2026-07-20 02:06:43 -04:00
builtbykev c2f6041406 STATE: off-box round trip CLOSED — 645 restored from the box copy
Phase 3 complete. The insurance chain is proven end to end rather than
assumed: dump -> validated -> pushed off-box -> verified on the box ->
pulled back down -> rebuilt into a live database.

Pulled vyndr-20260720-051158.dump FROM the Storage Box (not the local
copy) with the in-session key through the pinned host key, never
bypassing StrictHostKeyChecking. Restored into scratch Postgres 17: 715
archive objects, 42 public tables, ledger_entries with all 27 columns and
real spot-checked rows.

ASSERTION PASSED: ledger_entries restored 645 == live 645 (target >= 645).
model_snapshots restored 100/100, so the retention store shipped yesterday
is covered by backups from day one.

Records the operational gotcha the restore surfaced: the dump is written
by pg_dump 17 (Supabase 17.6) and pg_restore 16 CANNOT read it —
'unsupported version (1.16) in file header'. The first attempt failed on
exactly this. Any DR runbook must use PG17+ tooling. Restoring into
vanilla Postgres also logs 12 ignored errors (Supabase roles/extensions
absent locally) which are harmless.

Scratch DB torn down, pulled copy deleted, both dumps still on the box,
nightly cron untouched. No private key material echoed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SmNjJAwEnqHPtXbvSZR8kA
2026-07-20 01:28:29 -04:00
builtbykev 491e636b7f STATE: off-box backup working + verified on the box
Records off-box as WORKING with the root cause (key was only in Hetzner's
project store, never in the box's authorized_keys — the box previously
offered an EMPTY auth list) and the proof: offbox_ok:true, and the file
independently VERIFIED on the box via rsync --list-only through the pinned
host key (vyndr-20260720-051158.dump, 833,917 bytes, 05:12:28 UTC,
byte-identical to the local dump).

Env truth captured from the run output: key is correctly base64-decoded,
destination has no leading-slash bug.

Hardening recorded: host key statically pinned (accept-new gone, missing
pin refuses the push), remote dir guaranteed, failed required push now
pages at urgent with offbox_ok:false while the exit code still tracks
on-box durability.

Flags the ONE outstanding acceptance item honestly: the round-trip restore
is NOT done, because the dev box cannot authenticate to the Storage Box
(the authorized key is Kev's, not the in-session keypair) and the
container has no Postgres server. Lists both unblocks and the assertion
target (>= 645).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SmNjJAwEnqHPtXbvSZR8kA
2026-07-20 01:16:30 -04:00
builtbykev 7e150f9342 STATE.md: pin header + point to the orientation block 2026-07-20 00:10:15 -04:00
builtbykev 7ea0af2081 STATE.md: CURRENT STATUS + OPEN ITEMS orientation block
Top-of-file ground-truth block for orienting a fresh session.

Records what shipped tonight (probability layer revived 32/32, value
engine arc 1, grade-range work, backup durable on-box at 643/643,
model_snapshots retention live with 100 rows incl 36 refusals, ESPN
parser fix) WITH two honest qualifiers rather than a clean win: A still
does not emit in production so the A-RATED marketing hold stands, and EV
is overconfident (+62%/+61%/+56.9% captured, p_win clamps at 0.95) while
hero v2 already ranks on it.

OFF-BOX BACKUP recorded as NOT WORKING and deferred — never succeeded
once, every dump lives only on the Hetzner volume. Documents the two real
blockers fixed (missing base64 decode; container had rsync but no ssh
binary) and the remaining one: the Storage Box offers an EMPTY auth-method
list, which is an account refusing all auth rather than a wrong key.
Explicitly marks as UNVERIFIED that no Chrome/UI diagnostic was run — no
data on the SSH-support toggle, external reachability, project-vs-box key
scope, or any Hetzner outage — and lists those as untested hypotheses in
likelihood order rather than implying they were checked. The full
scratch-Postgres restore proof is recorded as still OWED.

Open items with status: settlement zero-pushes bug, ~28 props/day
unsettled, permanent model-version contamination (with the hard-cutoff
rule), A-grade unreachable, EV overconfidence, edge_pct broken scale, C4
CLV, consistency CV stopgap. Plus the three live credentials to rotate:
Storage Box password, VYNDR_INTERNAL_KEY (pasted in a transcript), and the
GitHub PAT still in .git/config.

Next queued: backtest harness (needs ~2wk history, currently holds one
night), settlement audit, opponent-strength sourcing (MLB solved via
statsapi pitching splits; NBA/WNBA open) behind the source-adapter
pattern, then the metrics engine gated on the harness.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SmNjJAwEnqHPtXbvSZR8kA
2026-07-20 00:10:02 -04:00
builtbykev 971f641d12 STATE: retention live + settlement findings + version contamination
Records model_snapshots as LIVE and verified capturing (100 rows over 2
cycles: MLB 14 graded/36 refused, WNBA 50 graded; features, grade_11,
p_win, ev_pct on 100% of graded rows).

First-ever refusal visibility: juiced_no_edge 18, rare_event_over_below_
line 13, insufficient_data 5 — the MLB gate refused 36 of 50 sides (72%),
now measurable for the first time.

Flags EV as OVERCONFIDENT and not fit to surface: first captured values
include +62.1%/+61%/+56.9%, which real markets do not offer. Cause is the
estimator clamping p_win at PROB_CEIL 0.95 off ~10 games. Hero v2 already
ranks on ev_pct, so it will pick the MOST overconfident read — calibration
must gate this before EV drives anything user-facing.

Logs the two settlement-correctness findings Kev asked to track (zero
pushes across 470 settled rows; ~28 props/day never settling) and the
ledger model-version contamination, with the rule that any backtest off
existing history must treat the 2026-07-19 fix boundary as a hard cutoff.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SmNjJAwEnqHPtXbvSZR8kA
2026-07-19 23:14:58 -04:00
builtbykev 8aafceaa3b STATE.md: pin header to cc8e478 2026-07-19 22:32:59 -04:00
builtbykev cc8e47884d STATE.md: backup is durable on-box and verified by read-back (643==643) 2026-07-19 22:32:59 -04:00
builtbykev 58ce1c3e56 STATE.md: header to deployed+fingerprinted HEAD 2026-07-19 18:58:26 -04:00
builtbykev a80868c4eb S63 fingerprint: probability layer verified live (p_win/ev_pct/model_odds)
POST /api/analyze/prop on prod returns p_win 0.523, ev_pct -10.4,
model_odds -109, confidence_basis grade_band, value false — every one of
which was absent on 100% of grades before this change. The value triplet
is whole (book -140 / fair -125 / model -109) and correctly refuses to
call a -140 price value when the model gives it 52.3%.

A-emission still pending the 01:00 UTC snapshot (opp_rank_stat populates
only when refreshTeamStats runs in a snapshot). MARKETING HOLD on A-RATED
copy stays until that passes. edge_pct scale remains broken (U-deg pt 2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SmNjJAwEnqHPtXbvSZR8kA
2026-07-19 18:58:12 -04:00
builtbykev 18bf3ecb51 Reconcile the record: STATE.md header + Model Train arc 1 spec (docs only)
Arc 1 (7a925f4) shipped without a spec and without a STATE.md entry — the
plan lived only in a session context that was lost. Both written from the
code on disk, not from memory.

- STATE.md: header was stale at a8e383e; now 7a925f4 (pushed, NOT yet
  deploy-fingerprinted). New top section records de-vig + EV + takeable/
  value gates + hero v2 + the value triplet, the real config values, and
  the 274/3289 -> 276/3306 test baseline.
- specs/model-train.md (NEW, per CLAUDE.md rule #1): every knob and its
  ACTUAL default (TAKEABLE_ODDS_CEILING -160, TAKEABLE_ODDS_MAX +200,
  VALUE_EV_THRESHOLD 2, JUICE_ODDS_FLOOR -400, RARE_EVENT_LINE_MAX 0.5);
  the gate AS BUILT (flat price-only refusal at -400 pre-feature, NOT
  edge-aware, no -250 wall; the -160..+200 band never refuses a grade and
  is enforced on the hero alone); the triplet + hero v2; and a checklist
  of what is NOT built.

Recorded honestly rather than assumed: EDGE_FLEX_WALL, HARD_JUICE_WALL,
LADDER_ODDS_MAX and MIN_RUNG_PROBABILITY do not exist in the codebase; no
frontend reads ev_pct/fair_odds/model_odds/book_odds/suppressed_reason yet;
the value fields are ungated to free tier; a second EV implementation
(processing/EVCalculator.js) still coexists with devig.evPct.

No engine code touched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SmNjJAwEnqHPtXbvSZR8kA
2026-07-19 17:56:09 -04:00
builtbykev f72f063e6f Suppress rare-event 0.5 unders (juiced, no-edge) — config-driven grade + board fix
Betting-logic audit: the CONSENSUS-vs-MODEL board flooded with fake reads like
"DOUBLES u0.5 · MODEL 0.2 · +edge" — the juiced under side of rare counting-stat
markets (doubles/triples/HR/SB), which is never a takeable edge and violates the
no-unders-default doctrine.

Report finding (item 3/4): the doubles projection is REAL per-player, not a flat
fallback — 'doubles' maps to a real game-log field (MLB_LOG_FIELD doubles→
doubles) and the live values varied (0.03/0.16/0.2/0.22). So no projection-gate
refusal for fakeness; the problem is purely structural (a rare event's real
projection always sits below a 0.5 line, so the under always "wins").

Fix (config-driven — src/config/rareEventMarkets.js, tunable stat list + line
threshold):
- Grade layer (analyzeViaEngine1): a rare-event UNDER at ≤0.5 is always REFUSED
  (grade null + suppressed flag/reason). A rare-event OVER at ≤0.5 is refused
  UNLESS the model genuinely projects the event above the line — because a
  0.2-over-0.5 carries the SAME |edge| as the suppressed under and would just
  take its rank on the board. The over grades normally once projection > line.
- Board layer (marketBreadth.collectBreadth): drops null-model rows so a
  suppressed/ungraded prop can't rank a "MODEL —" placeholder onto the board.

10 suppression tests + config locks; also fixed a settingsPage book assertion
left over from the ESPN→theScore swap. Suite 274/3289 green, web build exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 00:19:23 -04:00
builtbykev b8b954bb96 STATE.md: backup + founder-checkout tasks
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 23:08:57 -04:00
builtbykev 39c07a03b9 STATE.md: security + plumbing follow-up (items 0-7)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 13:57:45 -04:00
builtbykev b354d1d088 STATE.md: Truth-Everywhere Part 2 complete (all 8 items fingerprinted) + C4
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 01:56:45 -04:00