Skip to main content

Per-player override supersede — Test Cases

Feature: a player:admin override replaces the admin baseline cap (ADMIN-ONLY supersede, PR #826). player:ma / player:agent overrides do NOT supersede — they stack tightest. Spec: plans/per-player-override-supersede.md. Status: automated resolver coverage in backend/src/domain/exposureLimits/__tests__/resolveEffectiveLimits.test.ts; this doc adds the end-to-end matrix + dev1 manual steps.

Setup conventions

  • One tree: Admin → MA → Agent → Player, currency INR.
  • Limits written as maxExposure / perBet for one cell (e.g. Cricket, market-tier 1, tier 1).
  • "Default" at a level = no override row at that level (live-inherits the cascade).
  • Effective = what the betslip shows and what placement enforces (both via resolveEffectiveLimits).

Test matrix

#SetupEffective (betslip + enforce)Why
TC1admin→MA baseline 50/10; admin per-player override 500/100500/100player:admin supersedes the admin baseline; override binds even though it's looser
TC2baseline 50/10 + admin per-player override row exists but has no cell for this dimensionuncapped at admin level (baseline gone)supersede is presence-based: the override replaces the level; a silent cell = uncapped there
TC3as TC1, then switch the admin per-player override back to Default50/10 (baseline restored, live)clearing deletes the override row → no supersede → cascade admin baseline binds again
TC3bafter TC3, admin edits the MA baseline to 80/2080/20default player live-inherits the new baseline (no snapshot)
TC4baseline 50/10 + MA cap 500/100 + agent cap 500/100 + player:agent 300/6050/10admin-only: player:agent does NOT supersede — it stacks; tightest of {admin 50, agent 500, player:agent 300} = 50/10
TC5baseline 1000/200 + MA cap 500/100 + player:admin 800/150500/100player:admin supersedes the baseline (→800/150) but the MA cap (tighter, different level) still binds
TC6the reported scenario: baseline 50/10 + MA 500/100 + agent 500/100 + player:agent 500/100 + player:admin 500/100500/100player:admin drops the 50/10 baseline; surviving caps (MA 500, agent 500, player:agent 500) all 500/100
TC6bthe admin-only regression check: baseline 50/10 + ma→agent 50/10 + agent→player 500/100 + player:admin 500/10050/10player:admin drops the 50/10 baseline; the agent cap (carrying the ma→agent 50/10) survives and binds tightest = 50/10 (this is WHY supersede is admin-only)
TC7intermediate ancestor: Admin→MA→AgentA→AgentB→Player, AgentA cap 40/8, player:agent 500/100AgentA cap 40/8 still bindsplayer:agent does not supersede anything (admin-only); intermediate agent:<code> caps are never superseded regardless

"View Limits" (config view) — separate, unchanged

#ActionExpected
TC8Open agent/admin "View Limits" for a player with a per-player override at that layershows the applied/configured cells (the preset/custom set at that layer), NOT the effective ceiling — by design (getPlayerConfiguredLimits)
TC9Place-time enforcement vs betslip displayidentical — both run resolveEffectiveLimits (one function); a bet at the effective cap is accepted, one cent above is rejected

Automated coverage (resolveEffectiveLimits.test.ts)

CaseCovered by
TC1"player:admin override drops the admin baseline cap (override can be LOOSER and still bind)"
TC2"supersede is PRESENCE-based: baseline dropped even when the override is silent for this dimension"
TC3"Default / live-restore: with NO player:admin override the admin baseline binds again"
TC4 / TC6b"admin-only: player:agent does NOT supersede — the direct agent cap STILL binds (stacks tightest)" + the supersededCascadeLabels admin-only unit tests

Gaps left to manual / future automation: TC3b (live re-inherit after baseline edit), TC5/TC7 (multi-level + intermediate-ancestor), TC8/TC9 (config-view + place-time parity). TC5/TC7 are worth adding as resolver unit tests; TC9 is best as an order-placement integration test.

dev1 manual verification (deployed: feat/edit-preset-per-player)

  1. Admin → Downline → an MA's player. Note the betslip cap (baseline, e.g. 50/10).
  2. Admin sets a per-player admin-layer override of 500/100 on that player.
  3. Open the player betslip → cap shows 500/100 (TC1).
  4. Switch the override back to Default → betslip cap reverts to 50/10 (TC3).
  5. (TC5) Set the MA cap to 200/40, override to 500/100 → betslip shows 200/40 (tighter other level binds).
  6. (TC9) Try to place a bet whose projected win exceeds the effective cap → rejected with the binding layer; at/under → accepted.