S1 (a1): feature-promise audit — no claim survives unverified
PROMISE-AUDIT.md: every /pricing claim → verified/built/reworded. BUILT (was vapor): alt line ladder + edge ranking (same-features regrade at shifted lines, Desk-gated at the API), quarter-Kelly (engine quantile P(win) x real captured odds — either missing → no sizing), free-tier kill-condition locked previews. FIXED (was false): analyst 15/day cap vs the Founder 'Unlimited reads' promise → analyst unlimited; every '40+ factors' claim (real count: 22 named features) reworded truthfully in 7 files. VERIFIED: cascade alerts (real, wired), phi correlation, leg history, cross-book comparison, WC soccer, real-time feed. Locked by tests/unit/promiseAudit.test.js. Jest now ignores .claude/worktrees (parallel agents' suites no longer leak into runs). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Quarter-Kelly sizing (Session 62 / A1-S1 — the pricing page promised it;
|
||||
* now it exists). Pure math, no I/O.
|
||||
*
|
||||
* DATA SEMANTICS: Kelly needs a REAL win probability and REAL book odds.
|
||||
* p comes from the engine's quantile probability estimator (game-log based);
|
||||
* odds come from the captured book row. Either missing → null — a sizing
|
||||
* recommendation is never fabricated from confidence scores or defaults.
|
||||
*/
|
||||
|
||||
function americanToDecimal(american) {
|
||||
const a = Number(american);
|
||||
if (!Number.isFinite(a) || a === 0) return null;
|
||||
return a > 0 ? 1 + a / 100 : 1 + 100 / Math.abs(a);
|
||||
}
|
||||
|
||||
/**
|
||||
* quarterKelly(p, americanOdds) →
|
||||
* { full, quarter, pct } — fractions of bankroll (pct = quarter × 100,
|
||||
* rounded to 0.1) — or null when p/odds are unusable or the edge is
|
||||
* non-positive (Kelly says: no bet).
|
||||
*/
|
||||
function quarterKelly(p, americanOdds) {
|
||||
const prob = Number(p);
|
||||
if (!Number.isFinite(prob) || prob <= 0 || prob >= 1) return null;
|
||||
const dec = americanToDecimal(americanOdds);
|
||||
if (dec == null || dec <= 1) return null;
|
||||
const b = dec - 1;
|
||||
const full = (b * prob - (1 - prob)) / b;
|
||||
if (!Number.isFinite(full) || full <= 0) return null;
|
||||
const quarter = full / 4;
|
||||
return {
|
||||
full: Math.round(full * 1000) / 1000,
|
||||
quarter: Math.round(quarter * 1000) / 1000,
|
||||
pct: Math.round(quarter * 1000) / 10, // % of bankroll at quarter-Kelly
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = { quarterKelly, americanToDecimal };
|
||||
+12
-3
@@ -46,14 +46,23 @@ function lockKillConditions(list) {
|
||||
*/
|
||||
function applyTierGating(result, tierName) {
|
||||
if (!result || typeof result !== 'object') return result;
|
||||
|
||||
// Session 62 (A1-S1) — Desk-only intelligence is stripped at the API, not
|
||||
// just the adapter: alt line ladder + quarter-Kelly never leave the server
|
||||
// for lower tiers. (The pricing page sells them as Desk-only; the gate
|
||||
// makes that true at the wire.)
|
||||
const deskGated = { ...result };
|
||||
if (!canAccess(tierName, 'alt_line_ladder')) delete deskGated.alt_lines;
|
||||
if (!canAccess(tierName, 'kelly_sizing')) delete deskGated.kelly;
|
||||
|
||||
if (canAccess(tierName, 'reasoning_visible')) {
|
||||
// Paid tier — pass through unchanged.
|
||||
return result;
|
||||
// Paid tier — everything else passes through unchanged.
|
||||
return deskGated;
|
||||
}
|
||||
// Free tier: keep grade + confidence + edge_pct (the hook), redact
|
||||
// reasoning + kill condition explanations.
|
||||
return {
|
||||
...result,
|
||||
...deskGated,
|
||||
reasoning: lockReasoning(result.reasoning),
|
||||
kill_conditions_triggered: lockKillConditions(result.kill_conditions_triggered),
|
||||
tier_gated: true,
|
||||
|
||||
Reference in New Issue
Block a user