Commit Graph

18 Commits

Author SHA1 Message Date
builtbykev 1e9c808d99 docs: edge-shading challenger measured — flooding persists, input scale is the bug
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
2026-07-31 00:39:51 -04:00
builtbykev 896e6e1a00 docs: takeable tagging shipped, efficiency challenger blocked (board + state)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
2026-07-31 00:20:18 -04:00
builtbykev a6afac43cc report: market-efficiency scaling check — FLAT, mechanism structurally absent
Report-only. No threshold, grade, or efficiency value changed.

VERDICT: FLAT. marketEfficiency.js does not exist (zero occurrences of
market_efficiency / efficiency_score in src/ or web/src/). The spec's
0.85/0.60/0.55 values appear in grade_thresholds.json only as PROBABILITY
BANDS - a coincidental numeric overlap, not efficiency scores.

The base edge thresholds (MLB A:5%, NBA A:7%) do not exist either: engine1.js
has zero `edge` references, so the live grade is not an edge-vs-threshold
comparison at all. The specced rule threshold = base x efficiency has no host.

DISPOSITIVE: engine1.js contains ZERO `sport` references. computeFactors
receives no sport or market, so per-market OR per-sport scaling is structurally
impossible in the live grader - not merely unwired.

Phase 2: the matched-edge test is confounded (edge is not the grading input -
the same market emits both B and C at one edge). The aggregate that
discriminates: mean grade index wnba points 4.71 at mean edge 10.2 vs mlb hits
4.58 at 69.5 vs mlb total_bases 4.32 at 84.9 - the efficient market earns the
highest grades on one-eighth the edge, the opposite of spec.

PREMISE CORRECTION (measured): this order's opening claim that full-output and
collapsed grades "agree 100%" does not hold - on 512 rows carrying both they
agree 17.8%, with 33.8% differing by 3+ tiers. The prior discrimination result
stands (champion r=0.0050 null vs probability r=0.1313; MLB 0.0686 n.s. vs
0.2356 p~0.0004). Repo unchanged between orders. The collapse was not a
phantom and the re-adjudication list stays open.

Scope: flat thresholds are a grade-CALIBRATION gap only - the projection and
the CLV edge (which measured p_win, never the letter) are untouched, so this is
not a third shadow-model alarm. But the fix is NOT independently bounded: with
no threshold step to multiply, efficiency scaling presupposes probability
grading. It is rule R4 of specs/full-output-grade-mapping.md and belongs to
that MLB-first challenger.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
2026-07-30 23:56:48 -04:00
builtbykev 708f0fde5c report: full-output grade mapping spec + collapse cost measured
Report-only. Nothing built, reconnected, or promoted.

Premise corrected again: the three-layer engine is BUILT but NOT WIRED and NOT
DEPLOYED (0 python refs in every grade-path file, 0 python in Dockerfile; there
is no engine1Adapter). So no posterior/CI/similarity prior exists to inventory
or diff. Measured against the collapse that actually exists instead.

THREE collapses, not one: (A) estimateProbability's components discarded at
analyzeViaEngine1:521-524; (B) THE SEVERE ONE - p_win never reaches the grade
at all (engine1.js has zero probability references), so the probability is
excluded from grading rather than collapsed into it; (C) grade_thresholds.json
(probability->grade) read backwards to manufacture confidence.
Market-efficiency scaling is never computed - a gap, not a collapse.

MEASURED on 354 settled rows carrying the served letter and the locked pre-game
p_win (forward, not lookahead). Grade->outcome point-biserial r: champion letter
0.0050 (p~0.93, null) vs probability letter 0.1313 (p~0.013). Per sport: MLB
champ 0.0686 n.s. vs prob 0.2356 (p~0.0004); WNBA champ -0.0986 vs prob -0.1258
- BOTH INVERSE. The served letter is inverted between its only two populated
tiers (B 52.4% n=168 vs C 56.9% n=174).

Verdict: costly on MLB, and un-collapsing does NOT help WNBA -> the challenger
must be MLB-FIRST. Five falsifiable mapping rules specced, incl. R2
(uncertainty grades down) stated explicitly and droppable if it fails.

Hard requirement on the next order: persist per-row n, SE and pre-adjustment p,
or R2/R4 can never be adjudicated (not stored today).

Re-adjudication list flagged incl. proj-v1.1's NOT PROVEN verdict (judged
against the collapsed champion, so not final) and ROI-by-grade (with B/C
inverted, the MLB-C +4.57% segment is likely an artifact of a meaningless
letter).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
2026-07-30 23:47:11 -04:00
builtbykev dd98b0b614 report: model architecture recovery map — the live grade uses 0 of 3 specced layers
Archaeology only; nothing built, reconnected, or promoted.

The champion is two DISCONNECTED estimates: the letter is engine1's additive
factor index (zero references to p_win or any probability in engine1.js), and
p_win is probabilityEstimator's frequencyOver + 5 heuristic layers, computed
after and merely attached. The live grade path never calls the Python service.

The Python three-layer engine is NOT DEPLOYED — no python/pip in the
Dockerfile; app.js only health-checks it. So Layers 1-2 never shipped.
Layer 3 is wired BACKWARDS: grade_thresholds.json maps PROBABILITY->GRADE and
the live JS reads it in reverse to manufacture confidence from an
already-chosen letter. Per-sport market-efficiency scaling is specced-absent.

Consequence stated plainly: every metric audited to date is on the shadow
model, not the specced engine, which has never been measured.

Sport boundary TESTED not asserted: a new sport on the live path is a ~10-file
core edit with four documented silent-failure modes. Per-sport records DO
exist (sports.mlb n=526/62% vs pooled overall n=937/58%, each n>=20 gated),
but /api/accuracy ignores ?sport= and the pooled overall would absorb a new
sport. Park x weather confirmed challenger-only; xwOBA and leash absent.

Recovery map is dependency-ordered with MLB as the reference module.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
2026-07-30 23:16:34 -04:00
builtbykev f310608ca4 docs: top-graded selector fingerprinted — strip-after-rank boundary proven in prod
The anonymous live order (Brionna Jones edge 29.4 ahead of Rhyne Howard edge
42.9) is only explicable by server-side p_win ranking (.90 vs .745, both
takeable) while the payload carries no paid fields — the free caller got the
paid RANKING without the paid SIGNAL, on live data.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
2026-07-29 22:08:15 -04:00
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 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