Side Guard — reverse-middle & ladder caps
How SideGuard works
SideGuard is a family of structural gates that prevent correlated or conflicting bets across the same game. Five distinct checks layered together, all consulted by getSideGuardStatus(dom, now) in the badge eval pipeline. The gate consults both confirmed positions (positionsByBaseKey) and in-flight attempts (inFlightLockByKey) so cross-tab and cross-book races are caught.
The five checks
- Same-side ladder cap — caps open + in-flight bets on the same
{game, market, side}atautomation.ladderingMaxLinesPerSide(default 2). Pure geometry, not cooldown-gated. - Reverse-middle (totals + spreads) — blocks opposite-side bets at lines that create a both-LOSE region. Time-decoupled as of 2026.4.25.2 — fires whenever the geometry creates the bad shape, regardless of how long ago the prior was placed. Min gap:
sideGuardReverseMiddleMinGap(default 0.5). - Same-line opposite-side lock (added 2026.4.28.6) — blocks opposite-side bets at the EXACT same line on totals or spreads. Catches the degenerate case reverse-middle's gap test produces 0 for and skips (e.g. Cubs Over 13.5 + Cubs Under 13.5; Lakers +5 + Lakers −5). No time-based bypass; structural geometry.
- Matching-line flip cooldown — symmetric flip block within
sideGuardSymmetricFlipCooldownMs(default 5 min). Per-market overrides available viasideGuardMoneylineFlipCooldownMs/sideGuardMatchingSpreadFlipCooldownMs/sideGuardMatchingTotalFlipCooldownMs. - Generic opposite-side lock — broader cooldown (
sideGuardCooldownMs, default 45 min) for any opposite-side bet on the same game/market that doesn't hit one of the geometry tests above.
Order of checks (precedence)
Inside checkOppositeSnapshot, the geometry tests run in this order — first-fire wins:
- Reverse-middle total → "Reverse-middle total lock"
- Reverse-middle spread → "Reverse-middle spread lock"
- Same-line opposite-side → "Same-line opposite-side lock"
- Matching-line flip cooldown → "Matching {moneyline|spread|total} flip cooldown"
- Generic opposite-side lock → "Opposite side lock"
Worked examples (from production)
- Reverse-middle (caught): 2026-04-25 Nuggets/Wolves Under 218.5 + Over 224.5 + Under 215.5 — gap 6.0 between Under 218.5 and Over 224.5 created a both-lose band, blocked structurally regardless of time elapsed.
- Same-line opposite-side (caught after 4.28.6): 2026-04-27 Cubs @ Padres — Over 13.5 DK +110, then Under 13.5 BetMGM +110 placed 55 min later (well past 5-min flip cooldown). Reverse-middle's gap = 0 → skipped, fell through to canFlipSide which had lapsed. The new same-line opposite-side gate now catches this case structurally.
- Both-WIN middle (correctly NOT blocked): 2026-04-27 Pistons @ Magic — Under 200.5 + Over 193.5 created a both-WIN overlap zone (194–200), favorable shape. SideGuard correctly allowed this.
- Same-side ladder within cap (correctly NOT blocked): 2026-04-27 OKC @ Suns — Under 260.5 + Under 223.5, both Under same game total.
ladderingMaxLinesPerSide: 2permits 2 same-side bets by design. Lower to1to enforce stricter laddering.
Sign-based vs team-aware spread keying (2026.6.12.0)
Historically the subsystem keyed spreads/RL by normalizeSideKey, which returns "plus" / "minus" / "pk" based on the sign of the line, not team identity. (Totals are keyed separately as "over" / "under".) Two known blind spots, the second observed live on 2026-06-11 (Caesars Liberty +7.5 + Dream +5.5, same game — both plus, guard never engaged):
- Same-team line crossing zero live — Suns +8 pregame, then Suns −10 live. The reverse-middle-spread check sees
plus+minusand false-fires as if it were a split, even though both bets are the same team going the same direction (a double-down). - Cross-team same-sign pairs — Team A +3 + Team B +1 (both dogs) or A −3 + B −2 (both favorites) in the same game. Both register the same sign, so the opposite-side machinery (flip cooldown, reverse-middle, same-line lock) never engages; only the ladder cap (default 2) sees them, and a pair passes. Both-favorite pairs are true both-LOSE reverse middles.
As of 2026.6.12.0 the gate carries a parallel team-aware spread keying (sideGuardTeamAwareSpreads, default true): each spread snapshot resolves a team slug from the side text vs eventAway/eventHome (game-label fallback; unresolvable/ambiguous sides degrade to legacy sign keys). When BOTH ends of a pair resolve: same team = same side (laddering), different team = opposite side; the reverse-middle gap is −(lineA + lineB) for any sign combination, and "matching line" means mirror lines (lineA + lineB = 0). Cross-team both-dog middles are NOT structurally blocked — they route into the standard opposite-side cooldown with the EV/edge-improvement bypass, so deliberate middles survive.
Rollout: sideGuardTeamAwareSpreadsLogOnly (default true) means the legacy sign-based verdict still ENFORCES while divergences are logged ([sideGuard:teamAware]); the replay math on this page mirrors the enforced legacy behavior until the flag is promoted. Documented in memory/project_sideguard_sign_based.md.
Implementation: getSideGuardStatus, getSideGuardLockDetail, checkOppositeSnapshot, normalizeSideKey, reverseMiddleGapTotal, reverseMiddleGapSpread, and the inFlightLockByKey registry in osd-auto-edge-bb.js. Both evaluation entry points sync the in-flight registry from localStorage at the top so they see the same cross-tab view as the lock-acquire APIs (tryAcquireInFlightLock, getInFlightLockInfo).
Data
Controls
Run Settings
Sweep Setup
Guardrails
Segment Filters
Data Quality & Output
Summary
| Param | Baseline | Best | Bets | Baseline Score | Best Score | Delta |
|---|
Distribution
| Parameter Value | Bets | Pass Rate | Distinct Days | Green Day % | Worst Day | Win Rate | ROI | Profit | Stake | Avg EV |
|---|