You are 100% right—blending them mathematically ru...
생성일: 2026년 3월 1일
답변에 사용된 모델 GPT-5.2 Thinking by Chat01
생성일: 2026년 3월 1일
답변에 사용된 모델 GPT-5.2 Thinking by Chat01
You are 100% right—blending them mathematically ruins it because the 3-set median is always so high (28-30 games). Blending it forces the expected value way over the line, causing it to blindly spam OVERs. Great catch.
To make it just as accurate for OVERs as it is for UNDERs without breaking the math, we should leave the core 2-set gap (diff2) completely alone. Instead, we rewrite the Escape Valve so that it doesn't just "save" OVERs to NEUTRAL, but actively promotes them to STRONG when the 3rd set probability (p3) hits elite thresholds.
Here is the better fix.
// Escape valve: allow OVER to survive when 2-set shape is short IF the decider path is meaningfully alive.
// 32k calibration: tour-aware decider gates (WTA decider baseline lower → lower gates)
var _evDecOverThr = (_cbTourK === 'WTA') ? 0.38 : (_cbTourK === 'CH') ? 0.39 : 0.40;
var _evDecUnderThr = (_cbTourK === 'WTA') ? 0.28 : (_cbTourK === 'CH') ? 0.29 : 0.30;
if (!_isBo5 && (bandOver === "OPPOSE" || bandOver === "STRONG_OPPOSE")) {
if (Number.isFinite(p3) && Number.isFinite(med3) && Number.isFinite(line)) {
if (p3 >= _evDecOverThr && med3 >= (line + 2.5)) {
if (bandOver === "STRONG_OPPOSE") bandOver = "OPPOSE";
else bandOver = "NEUTRAL";
}
}
}
Replace it with this new tiered logic:
// Escape valve: allow OVER to survive and THRIVE when the decider path is highly alive.
var _evDecOverThr = (_cbTourK === 'WTA') ? 0.38 : (_cbTourK === 'CH') ? 0.39 : 0.40;
var _evDecUnderThr = (_cbTourK === 'WTA') ? 0.28 : (_cbTourK === 'CH') ? 0.29 : 0.30;
if (!_isBo5 && bandOver !== "STRONG") {
if (Number.isFinite(p3) && Number.isFinite(med3) && Number.isFinite(line)) {
if (med3 >= (line + 2.0)) {
// Create a ladder: The higher the 3rd set probability, the stronger the OVER support
if (p3 >= _evDecOverThr + 0.08) {
bandOver = "STRONG"; // Elite decider probability (e.g. >48%) -> STRONG OVER
} else if (p3 >= _evDecOverThr + 0.04) {
bandOver = (bandOver === "STRONG_OPPOSE") ? "NEUTRAL" : "SOFT";
} else if (p3 >= _evDecOverThr) {
if (bandOver === "STRONG_OPPOSE") bandOver = "OPPOSE";
else if (bandOver === "OPPOSE") bandOver = "NEUTRAL";
}
}
}
}
Why this works: It uses the fact that any match with a >48% chance of going 3 sets is an absolute structural OVER. It bypasses the 2-set median bias entirely.
Find this line (around line 17827):
var _clusterPick = (_p3c >= 0.50) ? _totSim.median3set : _totSim.median2set;
Replace it with:
text// Lower the visual projection threshold so it aligns with our new escape valve logic var _clusterPick = (_p3c >= 0.44) ? _totSim.median3set : _totSim.median2set;
This keeps the aggressive, highly accurate UNDER filtering
untouched, but gives OVERs a realistic path to being marked as STRONG when the matchup is a true coinflip
I’m trying to fix the clusters bc rn it’s only bossing for unders I don’t want to blend 2set and 3 set that’ll ruin it I think the patch I gave u is still wrong tho ? Can u got and read how my clusters logic currently works bc if we blend both together that’ll ruin it it’s already super accurate at picking unders I don’t wanna touch or ruin that
Update my script then send it as a downloadable txt link
After updating check for syntax and undefined issues
pythonpath="/mnt/data/Tennislocks_V18_Cluster_Governor.gs.txt" import os, re, textwrap, json, math, statistics text=open(path,'r',encoding='utf-8').read() len(text), text[:200] (887892, '/**\n * PATCH NOTE (2026-02-19):\n * - Restored getTotalsPick() to v3.0 logic (removed MIN_BET_PROB gate that blocked many OVERS).\n * - Fixed classifyPlayer() Big Server ace threshold from 0.5 to 0.05 (')
pythonimport re pattern = r"// Escape valve: allow OVER to survive when 2-set shape is short IF the decider path is meaningfully alive\." m = re.search(pattern, text) m.start() if m else None 580917
pythonstart = m.start()-500 end = m.start()+900 snippet = text[start:end] snippet[:1400] ' === "OPPOSE" || bandOver === "STRONG_OPPOSE") && _bo5PathSignal.over >= 2) {\n bandOver = (bandOver === "STRONG_OPPOSE") ? "OPPOSE" : "NEUTRAL";\n }\n if ((bandUnder === "OPPOSE" || bandUnder === "STRONG_OPPOSE") && _bo5PathSignal.under >= 2) {\n bandUnder = (bandUnder === "STRONG_OPPOSE") ? "OPPOSE" : "NEUTRAL";\n }\n if (bandOver === "SOFT" && _bo5PathSignal.over >= 3) bandOver = "STRONG";\n if (bandUnder === "SOFT" && _bo5PathSignal.under >= 3) bandUnder = "STRONG";\n }\n\n // Escape valve: allow OVER to survive when 2-set shape is short IF the decider path is meaningfully alive.\n // 32k calibration: tour-aware decider gates (WTA decider baseline lower → lower gates)\n var _evDecOverThr = (_cbTourK === \'WTA\') ? 0.38 : (_cbTourK === \'CH\') ? 0.39 : 0.40;\n var _evDecUnderThr = (_cbTourK === \'WTA\') ? 0.28 : (_cbTourK === \'CH\') ? 0.29 : 0.30;\n if (!_isBo5 && (bandOver === "OPPOSE" || bandOver === "STRONG_OPPOSE")) {\n if (Number.isFinite(p3) && Number.isFinite(med3) && Number.isFinite(line)) {\n if (p3 >= _evDecOverThr && med3 >= (line + 2.5)) {\n if (bandOver === "STRONG_OPPOSE") bandOver = "OPPOSE";\n else bandOver = "NEUTRAL";\n }\n }\n }\n\n // Symmetric escape valve for UNDER — when 2-set blowout path is strong.\n if (!_isBo5 && (bandUnder === "OPPOSE" || bandUnder === "STRONG_OPPOSE")) {\n if (Number.isFinite(p3) && Number.isFin'
python# Get the exact old block text between the escape valve comment and the next comment line old_start = text.find("// Escape valve: allow OVER to survive when 2-set shape is short IF the decider path is meaningfully alive.") old_end = text.find("// Symmetric escape valve for UNDER", old_start) old_block = text[old_start:old_end] old_block[:500], old_block[-200:], len(old_block) ('// Escape valve: allow OVER to survive when 2-set shape is short IF the decider path is meaningfully alive.\n // 32k calibration: tour-aware decider gates (WTA decider baseline lower → lower gates)\n var _evDecOverThr = (_cbTourK === \'WTA\') ? 0.38 : (_cbTourK === \'CH\') ? 0.39 : 0.40;\n var _evDecUnderThr = (_cbTourK === \'WTA\') ? 0.28 : (_cbTourK === \'CH\') ? 0.29 : 0.30;\n if (!_isBo5 && (bandOver === "OPPOSE" || bandOver === "STRONG_OPPOSE")) {\n if (Number.isFinite(p3) && Number.isFinite(med3', 'umber.isFinite(line)) {\n if (p3 >= _evDecOverThr && med3 >= (line + 2.5)) {\n if (bandOver === "STRONG_OPPOSE") bandOver = "OPPOSE";\n else bandOver = "NEUTRAL";\n }\n }\n }\n\n ', 706)
pythonunder_start = old_end under_snip = text[under_start:under_start+500] under_snip[:500] '// Symmetric escape valve for UNDER — when 2-set blowout path is strong.\n if (!_isBo5 && (bandUnder === "OPPOSE" || bandUnder === "STRONG_OPPOSE")) {\n if (Number.isFinite(p3) && Number.isFinite(med2) && Number.isFinite(line)) {\n if (p3 <= _evDecUnderThr && med2 <= (line - 1.5)) {\n if (bandUnder === "STRONG_OPPOSE") bandUnder = "OPPOSE";\n else bandUnder = "NEUTRAL";\n }\n }\n }\n\n // Match-type band adjustment: volatile matchups with high break tendency\n // shift ban'
pythonpattern2="var _clusterPick = (_p3c >= 0.50) ? _totSim.median3set : _totSim.median2set;" idx2=text.find(pattern2) idx2 766201
pythontext[idx2-300:idx2+200] ' | 3-set " + _totSim.median3set.toFixed(1) + " med (" + _totSim.avg3set.toFixed(1) + " mean)");\n // v7.2.9+: Cluster projection (mode-pick) to surface conditional 2-set vs 3-set expectations\n var _p3c = deciderPct;\n var _p3cAdj = (Number.isFinite(_p3setAdj) ? _p3setAdj : _p3c);\n var _clusterPick = (_p3c >= 0.50) ? _totSim.median3set : _totSim.median2set;\n lines.push(" Cluster projection: " + _clusterPick.toFixed(1) + "g (mode-pick) | E[T|2 sets] " + _totSim.avg2set.toF'
pythonoccurrences=[m.start() for m in re.finditer(re.escape(pattern2), text)] len(occurrences), occurrences[:5] (1, [766201])
pythonpat_ev="// Escape valve: allow OVER to survive when 2-set shape is short IF the decider path is meaningfully alive." len([m.start() for m in re.finditer(re.escape(pat_ev), text)]) 1
python# Locate diff2 definition near escape valve window = text[old_start-2000:old_start] # find last occurrence of "diff2" before old_start diff_pos = window.rfind("diff2") diff_pos 299
python# Extract context around that within window context = window[diff_pos-300:diff_pos+500] context ''
python# search within 4000 chars before escape valve pre = text[old_start-5000:old_start] # find all occurrences of 'diff2' in that pre for m2 in re.finditer(r'\bdiff2\b', pre): last=m2 last.start(), pre[last.start()-150:last.start()+200] (3299, ' return "OPPOSE";\n return "NEUTRAL";\n }\n\n var overSupport = Number.isFinite(diff2) ? diff2 : NaN;\n var underSupport = Number.isFinite(diff2) ? -diff2 : NaN;\n\n var bandOver = _bandSided_(overSupport, overStrongBand, overSoftBand);\n var bandUnder = _bandSided_(underSupport, underStrongBand, underSoftBand);\n\n // Bo5 multi-path band enrichment')
pythonidx_overSupport = text.find("var overSupport = Number.isFinite(diff2) ? diff2 : NaN;") idx_overSupport 579113
pythontext[idx_overSupport-2000:idx_overSupport+2000] 'MATCH STRUCTURE INDEX (MSI): shift cluster bands based on serve/return balance.\n var _msiHoldA = (ctx && Number.isFinite(ctx.holdA)) ? ctx.holdA : NaN;\n var _msiHoldB = (ctx && Number.isFinite(ctx.holdB)) ? ctx.holdB : NaN;\n var _msiShift = 0;\n if (Number.isFinite(_msiHoldA) && Number.isFinite(_msiHoldB)) {\n var _msiHoldSum = _msiHoldA + _msiHoldB;\n var _msiHoldGap = Math.abs(_msiHoldA - _msiHoldB);\n var _msiPwA = (ctx && Number.isFinite(ctx.pWinA)) ? ctx.pWinA : NaN;\n var _msiWpGap = Number.isFinite(_msiPwA) ? (Math.abs(_msiPwA - 0.5) * 2) : 0;\n var _msiGapAdj = Math.max(_msiHoldGap, _msiWpGap * 0.5);\n var _msiRaw = _msiHoldSum - 1.5 * _msiGapAdj;\n var _msiTourK = (ctx && ctx.tourLabel) ? _taperTourKey_(ctx.tourLabel) : \'ATP\';\n var _msiMid = (_msiTourK === \'WTA\' || _msiTourK === \'ITF\') ? 1.24 : (_msiTourK === \'CH\' ? 1.28 : 1.32);\n _msiShift = (_msiRaw - _msiMid) * 0.15;\n _msiShift = Math.max(-0.20, Math.min(0.20, _msiShift));\n if (ctx) ctx.msi = { raw: _msiRaw, mid: _msiMid, shift: _msiShift, tour: _msiTourK, wpGap: _msiWpGap, gapAdj: _msiGapAdj };\n }\n\n // Match-type interaction modifiers for cluster bands\n var _govMti = (ctx && ctx.matchTypeInteraction) ? ctx.matchTypeInteraction : null;\n var _govMtBandShift = 0;\n if (_govMti) {\n if (Number.isFinite(_govMti.breakTendency)) _govMtBandShift += _govMti.breakTendency * 0.15;\n if (Number.isFinite(_govMti.volatilityMod)) _govMtBandShift += _govMti.volatilityMod * 0.08;\n }\n\n var overStrongBand = strongBand - _msiShift;\n var overSoftBand = softBand - _msiShift;\n var underStrongBand = strongBand + _msiShift;\n var underSoftBand = softBand + _msiShift;\n\n function _bandSided_(supportVal, sBand, sfBand) {\n if (!Number.isFinite(supportVal)) return "NA";\n if (supportVal >= sBand) return "STRONG";\n if (supportVal >= sfBand) return "SOFT";\n if (supportVal <= -sBand) return "STRONG_OPPOSE";\n if (supportVal <= -sfBand) return "OPPOSE";\n return "NEUTRAL";\n }\n\n var overSupport = Number.isFinite(diff2) ? diff2 : NaN;\n var underSupport = Number.isFinite(diff2) ? -diff2 : NaN;\n\n var bandOver = _bandSided_(overSupport, overStrongBand, overSoftBand);\n var bandUnder = _bandSided_(underSupport, underStrongBand, underSoftBand);\n\n // Bo5 multi-path band enrichment: when Bo5, compute support from ALL set-path medians.\n // Each path that agrees with the chosen side counts as structural support.\n var _bo5PathSignal = { over: 0, under: 0, total: 0 };\n if (_isBo5 && Number.isFinite(line)) {\n if (Number.isFinite(_med3b5)) {\n _bo5PathSignal.total++;\n if (_med3b5 >= line) _bo5PathSignal.over++; else _bo5PathSignal.under++;\n }\n if (Number.isFinite(_med4set)) {\n _bo5PathSignal.total++;\n if (_med4set >= (line - 1)) _bo5PathSignal.over++;\n if (_med4set <= (line + 1)) _bo5PathSignal.under++;\n }\n if (Number.isFinite(_med5set)) {\n _bo5PathSignal.total++;\n if (_med5set >= (line + 2)) _bo5PathSignal.over++;\n if (_med5set <= (line - 2)) _bo5PathSignal.under++;\n }\n }\n\n // Bo5 path-based band softening: if multiple Bo5 paths support a side that the 2-set\n // median opposes, soften the opposition (5-set matches have more paths to the total).\n if (_isBo5 && _bo5PathSignal.total >= 2) {\n if ((bandOver === "OPPOSE" || bandOver === "STRONG_OPPOSE") && _bo5PathSignal.over >= 2) {\n bandOver = (bandOver === "STRONG_OPPOSE") ? "OPPOSE" : "NEUTRAL";\n }\n if ((bandUnder === "OPPOSE" || bandUnder === "STRONG_OPPOSE") && _bo5PathSignal.under >= 2) {\n bandUnder = (bandUnder === "STRONG_OPPOSE") ? "OPPOSE" : "NEUTRAL";\n }\n if (bandOver === "SOFT" && _bo5PathSignal.over >= 3) bandOver = "STRONG";\n if (bandUnder === "SOFT" && _bo5PathSignal.under >= 3) bandUnder = "STRONG";\n }\n\n // Escape valve: allow OVER to survive when 2-set shape is short IF the decider path is meaningfully alive.\n // 32k calibration: tour-aware decider gates (WTA decider baseline lower → lower gates'
python# Find nearest 'diff2' assignment before idx_overSupport pre2=text[idx_overSupport-5000:idx_overSupport] assigns=[m.start() for m in re.finditer(r'diff2\s*=', pre2)] assigns[-1], pre2[assigns[-1]-200:assigns[-1]+200] (2385, '= (ctx && Number.isFinite(ctx.clusterMedian4set)) ? Number(ctx.clusterMedian4set) : NaN;\n var _med5set = (ctx && Number.isFinite(ctx.clusterMedian5set)) ? Number(ctx.clusterMedian5set) : NaN;\n\n var diff2 = (Number.isFinite(line) && Number.isFinite(med2)) ? (med2 - line) : NaN;\n\n // Tour-aware cluster bands (33k calibration: WTA/ITF more volatile → wider bands required)\n var _cbTourK = (ctx && ')
python# find occurrences of 'bandOver' after old_start after=text[old_start:old_start+20000] # list unique lines containing 'bandOver' lines=[ln for ln in after.splitlines() if 'bandOver' in ln] lines[:30], len(lines) ([' if (!_isBo5 && (bandOver === "OPPOSE" || bandOver === "STRONG_OPPOSE")) {', ' if (bandOver === "STRONG_OPPOSE") bandOver = "OPPOSE";', ' else bandOver = "NEUTRAL";', ' if (adjBandOver === "SOFT" && bandOver === "NEUTRAL") bandOver = "SOFT";', ' if (adjBandOver === "STRONG" && bandOver === "SOFT") bandOver = "STRONG";', ' ctx.clusterBandOver = bandOver;', ' var _clusterMessy = (bandOver === "NEUTRAL" && bandUnder === "NEUTRAL" && edgeAbs < 0.015);', ' return (side === "OVER") ? bandOver : (side === "UNDER") ? bandUnder : "NA";', ' } else if (bandOver === "STRONG" && bandUnder !== "STRONG") {', ' } else if (bandUnder === "STRONG" && bandOver !== "STRONG") {', ' } else if (bandOver === "SOFT" && bandUnder === "NEUTRAL" && enginesWeak && !enginesSplit) {', ' } else if (bandUnder === "SOFT" && bandOver === "NEUTRAL" && enginesWeak && !enginesSplit) {'], 12)
python# locate the section where adjBandOver used idx_adj = text.find("adjBandOver", old_start) idx_adj 582307
pythontext[idx_adj-400:idx_adj+1000] '5)) {\n if (bandUnder === "STRONG_OPPOSE") bandUnder = "OPPOSE";\n else bandUnder = "NEUTRAL";\n }\n }\n }\n\n // Match-type band adjustment: volatile matchups with high break tendency\n // shift bands toward OVER; sweep-heavy matchups shift toward UNDER.\n if (_govMtBandShift !== 0 && Number.isFinite(overSupport)) {\n var adjOverSupport = overSupport + _govMtBandShift;\n var adjBandOver = _bandSided_(adjOverSupport, overStrongBand, overSoftBand);\n var adjBandUnder = _bandSided_(-adjOverSupport, underStrongBand, underSoftBand);\n if (adjBandOver === "SOFT" && bandOver === "NEUTRAL") bandOver = "SOFT";\n if (adjBandUnder === "SOFT" && bandUnder === "NEUTRAL") bandUnder = "SOFT";\n if (adjBandOver === "STRONG" && bandOver === "SOFT") bandOver = "STRONG";\n if (adjBandUnder === "STRONG" && bandUnder === "SOFT") bandUnder = "STRONG";\n }\n\n if (ctx) {\n ctx.clusterDiff2 = diff2;\n ctx.clusterBandOver = bandOver;\n ctx.clusterBandUnder = bandUnder;\n ctx.bo5PathSignal = _bo5PathSignal;\n }\n\n var edgeAbs = Math.abs(pO - 0.5);\n var enginesStrong = (edgeAbs >= 0.06);\n var enginesWeak = (edgeAbs < 0.03);\n var enginesSplit = (!agreeSide) || (Number.isFinite(disagree) && disagree >= 0.12) || (Number.isFinite(gapP) && gapP >= 0.12);\n\n var flipAllowed = (edgeAbs <= 0.05) || (pick.indexOf("LEAN") >= 0) || enginesSplit;\n\n // Bimodal/messy cluster '
python# extract further text[idx_adj+1000:idx_adj+2200] 'detection (for Rule 5)\n // STRICT: only declare messy when truly directionless — prefer LEANs over PASS\n var _clusterMessy = (bandOver === "NEUTRAL" && bandUnder === "NEUTRAL" && edgeAbs < 0.015);\n if (_isBo5 && _bo5PathSignal.total >= 3) {\n var _pathsAnyOver = _bo5PathSignal.over;\n var _pathsAnyUnder = _bo5PathSignal.under;\n if (_pathsAnyOver >= 1 && _pathsAnyUnder >= 1 && Math.abs(_pathsAnyOver - _pathsAnyUnder) === 0) {\n _clusterMessy = true;\n }\n }\n if (Number.isFinite(med2) && Number.isFinite(med3) && Math.abs(med3 - med2) >= 12) {\n _clusterMessy = true;\n }\n\n function _sideFromPick_(pk) {\n if (pk.indexOf("OVER") >= 0) return "OVER";\n if (pk.indexOf("UNDER") >= 0) return "UNDER";\n return "";\n }\n\n function _bandForSide_(side) {\n return (side === "OVER") ? bandOver : (side === "UNDER") ? bandUnder : "NA";\n }\n\n function _fmtCluster_() {\n var parts = [];\n var _fl = (ctx && Number.isFinite(ctx.fairLine)) ? ctx.fairLine : ((ctx && Number.isFinite(ctx.fairLineMC)) ? ctx.fairLineMC : NaN);\n var _ln = (ctx && Number.isFinite(ctx.line)) ? ctx.line : NaN;\n if (Number.isFinite(_fl) && Number.isFinite(_ln)) {\n var _flDiff = _fl - _l'
python# within 8000 chars after idx_adj find "Rule 1" region=text[idx_adj:idx_adj+20000] for phrase in ["Rule 1", "Rule1", "RULE 1"]: print(phrase, region.find(phrase))
pythonpos = idx_adj + 4700 text[pos-500:pos+2500] '!enginesSplit) {\n pick = "LEAN UNDER";\n ctx.reason = "cluster tiebreak (soft, engines weak)";\n ctx.reasonDetail = "UNDER " + _fmtCluster_();\n }\n }\n\n // Rules 1-3: Engines have chosen a side — cluster governs conviction\n var side0 = _sideFromPick_(pick);\n if (side0) {\n var band0 = _bandForSide_(side0);\n var sideOpp = (side0 === "OVER") ? "UNDER" : "OVER";\n var bandOpp = _bandForSide_(sideOpp);\n\n if (enginesStrong && !enginesSplit) {\n // Engines agree (strong edge)\n if (band0 === "STRONG" || band0 === "SOFT") {\n // Rule 1: Engines agree + cluster confirms → keep (promotion deferred to Final Authority)\n if (!ctx.reason) {\n ctx.reason = "cluster confirm";\n ctx.reasonDetail = side0 + " " + _fmtCluster_();\n }\n } else if (band0 === "NEUTRAL") {\n // Rule 2: Engines agree + cluster neutral → keep side, lower confidence\n if (pick === side0) pick = "LEAN " + side0;\n ctx.forceTotalsTierLow = true;\n if (!ctx.reason) {\n ctx.reason = "cluster neutral";\n ctx.reasonDetail = side0 + " " + _fmtCluster_();\n }\n } else if (band0 === "STRONG_OPPOSE") {\n // Rule 3: Engines agree + cluster strongly opposes → veto\n ctx.reason = "cluster veto";\n ctx.reasonDetail = side0 + " " + _fmtCluster_();\n return "PASS";\n } else if (band0 === "OPPOSE") {\n // Rule 3: Engines agree + cluster opposes → downgrade hard\n if (pick === side0) pick = "LEAN " + side0;\n ctx.forceTotalsTierLow = true;\n if (!ctx.reason) {\n ctx.reason = "cluster downgrade";\n ctx.reasonDetail = side0 + " " + _fmtCluster_();\n }\n }\n } else {\n // Engines weak or split\n if (bandOpp === "STRONG" && flipAllowed) {\n // Rule 4: Engines split + cluster strongly favors opposite → cluster breaks tie\n pick = "LEAN " + sideOpp;\n ctx.reason = "cluster flip";\n ctx.reasonDetail = side0 + "->" + sideOpp + " " + _fmtCluster_();\n } else if (band0 === "STRONG") {\n // Rule 4: Engines weak + cluster strongly confirms → keep full conviction\n if (!ctx.reason) {\n ctx.reason = "cluster confirm";\n ctx.reasonDetail = side0 + " " + _fmtCluster_();\n }\n } else if (band0 === "SOFT") {\n // Rule 1 (weak engines): cluster softly confirms → keep but cap to LEAN\n if (pick === side0 && enginesSplit) pick = "LEAN " + side0;\n if (!ctx.reason) {\n ctx.reason = "cluster confirm";\n ctx.reasonDetail = side0 + " " + _fmtCluster_();\n }\n } else if (band0 === "OPPOSE" || band0 === "STRONG_OPPOSE") {\n // Rule 3 (weak engines): cluster opposes → veto\n ctx.reason = "cluster veto";\n ctx.reasonDetail = side0 + " " + _fmtCluster_();\n return "PASS";\n } else if (band0 === "NEUTRAL") {\n // Rule 5: Engines split + cluster neutral/messy → PASS or low confidence\n '
pythontext[pos+2500:pos+4500] ' if (_clusterMessy || (enginesSplit && edgeAbs < 0.02)) {\n ctx.reason = "cluster messy";\n ctx.reasonDetail = side0 + " " + _fmtCluster_();\n return "PASS";\n }\n ctx.reason = "cluster neutral";\n ctx.reasonDetail = side0 + " " + _fmtCluster_();\n if (edgeAbs < 0.01) return "PASS";\n if (pick === side0) pick = "LEAN " + side0;\n ctx.forceTotalsTierLow = true;\n }\n }\n }\n\n // ===== Step 3a: OverScore refinement (OVER only) =====\n // Symmetric to UnderScore: sizing refinement only (may DOWNGRADE OVER -> LEAN OVER).\n if (pick === "OVER" || pick === "LEAN OVER") {\n var pOver = pO; // no-push over probability (combined)\n var ltO = (ctx && Number.isFinite(ctx.leftTail)) ? Number(ctx.leftTail) : NaN;\n var blowO = (ctx && Number.isFinite(ctx.blowoutBucket)) ? Number(ctx.blowoutBucket) : NaN; // line-relative left tail proxy\n var pDecO = (ctx && Number.isFinite(ctx.pDecider)) ? Number(ctx.pDecider) : NaN;\n var rtO = (ctx && Number.isFinite(ctx.rightTail)) ? Number(ctx.rightTail) : NaN;\n var cmO = (ctx && Number.isFinite(ctx.centralMass)) ? Number(ctx.centralMass) : NaN;\n\n // Anchors (tour/line-aware inputs already baked into tails):\n var rtAnchorO = (ctx && Number.isFinite(ctx.overScoreRtAnchor)) ? Number(ctx.overScoreRtAnchor) : 0.12;\n var ltAnchorO = (ctx && Number.isFinite(ctx.overScoreLtAnchor)) ? Number(ctx.overScoreLtAnchor) : 0.10;\n var decAnchorO = (ctx && Number.isFinite(ctx.overScoreDecAnchor)) ? Number(ctx.overScoreDecAnchor) : 0.34;\n var cmAnchorO = (ctx && Number.isFinite(ctx.overScoreCmAnchor)) ? Number(ctx.overScoreCmAnchor) : 0.24;\n\n var aO = (ctx && Number.isFinite(ctx.overScoreAlpha)) ? Number(ctx.overScoreAlpha) : 0.40; // right tail help\n var bO = (ctx && Number.isFinite(ctx.overScoreBeta)) ? Number(ctx.overScoreBeta) : 0.35; // decider help\n var gO = (ctx && Number.isFinite(ctx.overScoreGamma)) ? Number(ctx.overScoreGamma) '
pythonfa_idx=text.find("Final Authority", idx_adj) fa_idx 587148
pythontext[fa_idx-600:fa_idx+900] '";\n ctx.reason = "cluster tiebreak (soft, engines weak)";\n ctx.reasonDetail = "UNDER " + _fmtCluster_();\n }\n }\n\n // Rules 1-3: Engines have chosen a side — cluster governs conviction\n var side0 = _sideFromPick_(pick);\n if (side0) {\n var band0 = _bandForSide_(side0);\n var sideOpp = (side0 === "OVER") ? "UNDER" : "OVER";\n var bandOpp = _bandForSide_(sideOpp);\n\n if (enginesStrong && !enginesSplit) {\n // Engines agree (strong edge)\n if (band0 === "STRONG" || band0 === "SOFT") {\n // Rule 1: Engines agree + cluster confirms → keep (promotion deferred to Final Authority)\n if (!ctx.reason) {\n ctx.reason = "cluster confirm";\n ctx.reasonDetail = side0 + " " + _fmtCluster_();\n }\n } else if (band0 === "NEUTRAL") {\n // Rule 2: Engines agree + cluster neutral → keep side, lower confidence\n if (pick === side0) pick = "LEAN " + side0;\n ctx.forceTotalsTierLow = true;\n if (!ctx.reason) {\n ctx.reason = "cluster neutral";\n ctx.reasonDetail = side0 + " " + _fmtCluster_();\n }\n } else if (band0 === "STRONG_OPPOSE") {\n // Rule 3: Engines agree + cluster strongly opposes → veto\n ctx.reason = "cluster veto";\n ctx.reasonDetail = side0 + " " + _fmtCluster_();\n return "PASS";\n } else if (band0 === "OPPOSE") {\n // Rule 3: Engines agree + cluster opposes → downgrade hard\n if (pick === side0) pick = "LEAN " + side0;\n '
python# find "Step 4" or "Final Authority" in region region2=text[idx_adj:idx_adj+25000] for phrase in ["Final Authority", "Step 4", "promotion", "PROMOTE"]: print(phrase, region2.find(phrase))
pythonsection=text[pos+4500:pos+15000] # search for pick promotions to STRONG for pat in ["STRONG OVER", "STRONG UNDER", 'pick = "OVER"', 'pick = "UNDER"', 'pick = "LEAN OVER"', 'pick = "LEAN UNDER"']: print(pat, section.find(pat))
pythonidx_lean_over=section.find('pick = "LEAN OVER"') text[pos+4500+idx_lean_over-250:pos+4500+idx_lean_over+400] '\';\n var _convScoreThr = (_convTourK === \'WTA\') ? 0.61 : (_convTourK === \'ITF\') ? 0.63 : (_convTourK === \'CH\') ? 0.59 : 0.58;\n if (pick === "OVER") {\n if (scoreO < _convScoreThr && !(Number.isFinite(pOver) && pOver >= minLeanPO)) {\n pick = "LEAN OVER";\n if (!ctx.reason) {\n ctx.reason = "over-score";\n ctx.reasonDetail = ctx.overScoreDetail;\n }\n }\n }\n }\n\n // ===== Step 3b: UnderScore refinement (UNDER only) =====\n if (pick === "UNDER" || pick === "LEAN UNDER") {\n var pUnder = 1 - pO; // no-push under probability (combined)\n var blow = (ctx && Number.isFinite(ctx.blowoutBucket)) ?'
pythonidx_getTotals = text.find("function getTotalsPick") idx_getTotals 564600
pythontext[idx_getTotals:idx_getTotals+600] 'function getTotalsPick(pOverNoPush, ctx) {\n ctx = ctx || {};\n // Deterministic explanation key (used by MATCH_PREVIEW output)\n ctx.reason = "";\n ctx.reasonDetail = "";\n\n // NOTE: pOverNoPush is expected to be the combined totals probability engine output\n // (MC + Markov blend when available). Raw MC no-push pOver can be passed via ctx.pOverMC.\n var pO = Number(pOverNoPush);\n if (!Number.isFinite(pO)) {\n ctx.reason = "invalid probability";\n return "PASS";\n }\n pO = clamp01(pO);\n\n // Raw engines (diagnostic + disagreement)\n var pMC = (ctx && Number.isFinite(ctx.pOverMC)) ? clam'
python# find within getTotalsPick function the initial 'pick =' assignment maybe sub=text[idx_getTotals:idx_getTotals+60000] # find first occurrence of 'pick =' after function start m_pick=re.search(r'\bpick\s*=\s*"', sub) m_pick.start() if m_pick else None 9702
pythonsub[m_pick.start()-400:m_pick.start()+400] ' var _epMaxClamp = _epIsWta ? 0.055 : _epIsCh ? 0.058 : 0.060;\n var _epLeanMult = _epIsWta ? 0.50 : _epIsCh ? 0.52 : 0.55;\n var _epLeanMin = _epIsWta ? 0.009 : _epIsCh ? 0.0085 : 0.008;\n minEdge = Math.max(_epMinClamp, Math.min(_epMaxClamp, minEdge));\n var leanEdge = Math.max(_epLeanMin, minEdge * _epLeanMult);\n\n // ===== Step 1: Tentative side from combined totals engines (pO) =====\n var pick = "PASS";\n if (pO >= (0.50 + minEdge)) pick = "OVER";\n else if (pO <= (0.50 - minEdge)) pick = "UNDER";\n else if (pO >= (0.50 + leanEdge)) pick = "LEAN OVER";\n else if (pO <= (0.50 - leanEdge)) pick = "LEAN UNDER";\n\n // Cluster override: when severe+fragile engines disagree but cluster strongly supports a side,\n // force LEAN pick in that direction even if edge thresholds alone would PA'
python# find all occurrences of 'Final Authority' in getTotalsPick substring for m in re.finditer("Final Authority", sub): print(m.start())
pythonpos2 = idx_getTotals + 22548 text[pos2-500:pos2+1200] 'fmtCluster_();\n }\n }\n\n // Rules 1-3: Engines have chosen a side — cluster governs conviction\n var side0 = _sideFromPick_(pick);\n if (side0) {\n var band0 = _bandForSide_(side0);\n var sideOpp = (side0 === "OVER") ? "UNDER" : "OVER";\n var bandOpp = _bandForSide_(sideOpp);\n\n if (enginesStrong && !enginesSplit) {\n // Engines agree (strong edge)\n if (band0 === "STRONG" || band0 === "SOFT") {\n // Rule 1: Engines agree + cluster confirms → keep (promotion deferred to Final Authority)\n if (!ctx.reason) {\n ctx.reason = "cluster confirm";\n ctx.reasonDetail = side0 + " " + _fmtCluster_();\n }\n } else if (band0 === "NEUTRAL") {\n // Rule 2: Engines agree + cluster neutral → keep side, lower confidence\n if (pick === side0) pick = "LEAN " + side0;\n ctx.forceTotalsTierLow = true;\n if (!ctx.reason) {\n ctx.reason = "cluster neutral";\n ctx.reasonDetail = side0 + " " + _fmtCluster_();\n }\n } else if (band0 === "STRONG_OPPOSE") {\n // Rule 3: Engines agree + cluster strongly opposes → veto\n ctx.reason = "cluster veto";\n ctx.reasonDetail = side0 + " " + _fmtCluster_();\n return "PASS";\n } else if (band0 === "OPPOSE") {\n // Rule 3: Engines agree + cluster opposes → downgrade hard\n if (pick === side0) pick = "LEAN " + side0;\n ctx.forceTotalsTierLow = true;\n if (!ctx.reason) {\n ctx.reason = "cluster downgrade";\n ctx.reasonDetail = side0 + " " + _fmtCluster_();\n }\n }\n } else {\n // Engines weak or split\n if (bandOpp === "STRONG" && flipAllowed) {\n // Rule 4: Engines'
pythonfor phrase in ["Step 4", "Step 3c", "Step 3d", "Step 4:", "Step 5"]: print(phrase, [m.start() for m in re.finditer(phrase, sub)][:5])
pythonfor m in re.finditer(r"Step 3", sub): print(m.start(), sub[m.start():m.start()+80])
python# find next "Final Authority" after step3b fa = sub.find("Final Authority", 28819) fa -1
python# around comment "Cluster override" after pick selection pos_override = sub.find("Cluster override", m_pick.start()) sub[pos_override-400:pos_override+1200] 'in(_epMaxClamp, minEdge));\n var leanEdge = Math.max(_epLeanMin, minEdge * _epLeanMult);\n\n // ===== Step 1: Tentative side from combined totals engines (pO) =====\n var pick = "PASS";\n if (pO >= (0.50 + minEdge)) pick = "OVER";\n else if (pO <= (0.50 - minEdge)) pick = "UNDER";\n else if (pO >= (0.50 + leanEdge)) pick = "LEAN OVER";\n else if (pO <= (0.50 - leanEdge)) pick = "LEAN UNDER";\n\n // Cluster override: when severe+fragile engines disagree but cluster strongly supports a side,\n // force LEAN pick in that direction even if edge thresholds alone would PASS.\n if (pick === "PASS" && ctx && ctx.clusterForceLean) {\n pick = "LEAN " + ctx.clusterForceLean;\n }\n\n // If winner engines are bimodal, do not allow "strong" totals tags.\n if (ctx && ctx.capTotalsToLean) {\n if (pick === "OVER") pick = "LEAN OVER";\n else if (pick === "UNDER") pick = "LEAN UNDER";\n }\n\n // ===== Step 2: CLUSTER GOVERNANCE LAYER (Final Authority on conviction) =====\n //\n // ARCHITECTURE: Cluster is the LAST WORD on conviction, not an engine.\n // 1. MC creates the full world (distribution, pOver, set paths).\n // 2. Markov gives the independent math cross-check.\n // 3. Cluster reads the match shape and decides whether the edge is clean enough to trust.\n //\n // GOVERNANCE MATRIX (5 rules):\n // Rule 1: Engines agree + cluster confirms → keep or promote\n // Rule 2: Engines agree + cluster neutral → keep side, lower confidence\n // Rule 3: Engines agree + cluster opposes → downgrade hard or veto\n // Rule 4: Engines split/weak + cluster strong → cluster break'
python# Prepare new escape valve block new_block = """// Escape valve: allow OVER to survive and THRIVE when the decider path is highly alive. var _evDecOverThr = (_cbTourK === 'WTA') ? 0.38 : (_cbTourK === 'CH') ? 0.39 : 0.40; var _evDecUnderThr = (_cbTourK === 'WTA') ? 0.28 : (_cbTourK === 'CH') ? 0.29 : 0.30; if (!_isBo5 && bandOver !== "STRONG") { if (Number.isFinite(p3) && Number.isFinite(med3) && Number.isFinite(line)) { if (med3 >= (line + 2.0)) { // Create a ladder: the higher the 3rd set probability, the stronger the OVER support if (p3 >= _evDecOverThr + 0.08) { bandOver = "STRONG"; // Elite decider probability -> STRONG OVER if (ctx) ctx.clusterEvOverPromote = true; // used later to allow LEAN->OVER (888772, 880)
pythonout_path="/mnt/data/Tennislocks_V18_Cluster_Governor_v18.1_EscapeValveFix.gs.txt" open(out_path,'w',encoding='utf-8').write(text2) out_path '/mnt/data/Tennislocks_V18_Cluster_Governor_v18.1_EscapeValveFix.gs.txt'
python# Confirm old comment not present, new comment present ("survive when 2-set shape is short" in text2, "survive and THRIVE" in text2) (False, True)
python("(_p3c >= 0.50)" in text2, "(_p3c >= 0.44)" in text2) (False, True)
pythontext2.count("Cluster promotion (OVER only)"), text2.count("ctx.clusterEvOverPromote") (1, 2)
I pulled up your uploaded script (Tennislocks_V18_Cluster_Governor.gs.txt) and traced how the totals cluster governor actually works right now:
pO → sets pick to OVER / UNDER / LEAN OVER / LEAN UNDER / PASS based on minEdge + leanEdge.diff2 = med2 - line (no blending), with tour-aware bands + MSI shift + match-type shift + Bo5 path enrichment.So your instinct is right: don’t touch diff2 or blend medians. The clean fix is: upgrade the escape valve + give it a real promotion hook (otherwise “bandOver = STRONG” doesn’t reliably turn into an OVER when engines are only LEAN OVER).
p3 + med3 as a governor override (not a blend).bandOver to "STRONG" only when:
med3 >= line + 2.0, andp3 >= _evDecOverThr + 0.08 (elite decider)ctx.clusterEvOverPromote = true so we can promote the final pick cleanly.Right before OverScore refinement, I added:
pick === "LEAN OVER" and the escape valve hit elite (ctx.clusterEvOverPromote) and engines aren’t split (!enginesSplit) and you’re not in capTotalsToLean, then:
LEAN OVER → OVERThat’s what makes the “elite decider = structural OVER” actually show up as a strong tag without blending anything.
_p3c >= 0.50 → _p3c >= 0.44node --check on a .js copy).ctx.clusterEvOverPromote (a context property), and referenced existing in-scope vars/functions (bandOver, enginesSplit, _fmtCluster_, etc.).Here’s the updated script as a downloadable txt: