End-to-end test report — 32/32 passing

Every user journey of the B2B agent console, driven against the live UI and the stateful mock API, with a screen recording, granular steps and assertions per case.

Total cases
32
Passed
32
Failed
0
Pass rate
100%
Assertions
65
Videos
32
Wall time
33.6s
SSO login then MFA lands on the scoped dashboard
J01 · Login + MFA · J01-login-mfa · ui · 289ms
PASS
A valid agent logs in and completes MFA to reach their console.

Steps

  • Open the login page
  • Pick the @sm_raj demo identity and continue
  • Enter the 6-digit MFA code 123456
  • Wait for the dashboard

Assertions

  • Landed on the dashboard route
  • KPI "Today's P&L" is shown
Wrong MFA code is rejected (stays on login)
J01 · Login + MFA · J01-wrong-mfa · ui · negative · 219ms
PASS
An incorrect OTP must not grant access; a clear error is shown.

Steps

  • Open login and continue past credentials as @sm_raj
  • Enter an INVALID code 000000
  • Observe rejection

Assertions

  • Error message shown for bad code
  • Still on the login page (no access granted)
Unknown account fails gracefully (no blank app)
J01 · Login + MFA · J01-unknown-account · ui · negative · 203ms
PASS
A username with no console access is rejected with a message, not a broken screen.

Steps

  • Open login
  • Type an unknown username and continue
  • Observe graceful error

Assertions

  • A graceful error is shown (not a blank app)
Dashboard shows KPIs, exposure alerts and the live ticker
J02 · Dashboard · J02-dashboard · ui · 603ms
PASS
The landing surface summarises the book scoped to the caller subtree.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Check the exposure alert banners

Assertions

  • KPI "Today's P&L" visible
  • KPI "Live exposure" visible
  • KPI "Active members" visible
  • An exposure alert banner is shown
  • The live downline-bets ticker strip is present
Expand the agent tree and open a node detail drawer
J03 · Downline browse · J03-downline-browse · ui · 727ms
PASS
Navigate the hierarchy and inspect a child node.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Go to Downline
  • Expand the root node
  • Wait for child Amit (Master) to load
  • Open the node detail drawer

Assertions

  • RLS scoping banner explains subtree-only visibility
  • Child node Amit (Master) appears under the root
  • Drawer shows Credit & exposure
  • Drawer shows per-game rates
Create a sub-node (inherits mode, level directly below)
J04 · Create child node · J04-create-child · ui · 933ms
PASS
An upline creates a valid child node.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Downline and the Create sub-node modal
  • Fill the new node details
  • Submit
  • Wait for success toast

Assertions

  • Modal states the mode is inherited (not selectable)
  • Success toast confirms the node was created
Child credit limit above the upline remaining is rejected
J04 · Create child node · J04-credit-over-upline · ui · negative · 899ms
PASS
Server enforces creditLimit ≤ caller remaining; UI surfaces the allowed max.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open the Create sub-node modal
  • Enter a credit limit far above the upline remaining
  • Observe rejection with allowed max

Assertions

  • Rejected with an "exceeds remaining credit" error
  • A "Use max" shortcut with the allowed maximum is offered
A game rate outside the allowed band is rejected
J05 · Game rates · J05-rate-out-of-band · ui · negative · 663ms
PASS
A settle rate below the upline rate must be refused (monotonicity).

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Amit's rate editor
  • Wait for the rates table
  • Set the first game rate below the upline (0.05)
  • Save
  • Observe out-of-band rejection

Assertions

  • Save rejected — rate outside the allowed band
A valid in-band rate saves (effective-dated)
J05 · Game rates · J05-rate-valid-save · ui · 702ms
PASS
Setting a rate within the band succeeds and is effective-dated.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Amit's rate editor
  • Wait for the rates table
  • Set the first game rate to a valid 0.50
  • Save
  • Wait for success toast

Assertions

  • Rates saved successfully
Give credit: review → step-up → pending → confirmed (never optimistic)
J06 · Credit give/take · J06-give-confirmed · ui · 2.2s
PASS
A money move shows a pending state and resolves only on ledger confirmation.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Credit & Wallet
  • Select child Amit, direction Give, amount 250000
  • Review the transfer
  • Confirm the amount
  • Complete step-up authentication
  • Wait for ledger confirmation

Assertions

  • Confirm sheet shows the "never optimistic" notice
  • Transfer reaches the Confirmed state
  • A confirmation toast is shown
Replaying the same Idempotency-Key does not double-move
J06 · Credit give/take · J06-idempotency · api · 643ms
PASS
The ledger is idempotent: a replayed transfer returns the original, no second move.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Credit (context)
  • POST a transfer with an Idempotency-Key
  • Replay the identical request with the SAME key

Assertions

  • First transfer accepted
  • Replay returns the SAME transaction id (no double move)
Give beyond remaining credit is blocked with the max shown
J06 · Credit give/take · J06-over-limit · ui · negative · 1.0s
PASS
The UI prevents a transfer above the caller remaining credit.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Credit and select a child
  • Enter an amount far above remaining credit

Assertions

  • Inline error: exceeds remaining credit
  • Review button is disabled
Worst-case exposure drills category → event
J07 · Live exposure · J07-exposure-drilldown · ui · 681ms
PASS
Exposure is the worst outcome per market, aggregated and drillable.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Live Risk
  • Drill into the Cricket category
  • Wait for the event level

Assertions

  • Total worst-case exposure headline is shown
  • MAX-not-sum explainer is present
  • Drilled to events (IND vs AUS visible)
  • Breadcrumb shows the Cricket path
A node in the warning band renders the warning state
J07 · Live exposure · J07-warn-band · ui · 669ms
PASS
When exposure ≥ 80% of the limit, the console warns.

Steps

  • Log in as @sub_kiran (password "demo") and pass MFA (code 123456)
  • Open Live Risk for the retail-edge node
  • Wait for the warning banner

Assertions

  • Warning-band banner is shown for the near-limit node
Exposure for a node outside the subtree is not returned
J07 · Live exposure · J07-rls-cross-subtree · api · negative · 622ms
PASS
RLS blocks reading a sibling branch — no existence confirmation.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Request exposure for a POINT-tree node (outside subtree)

Assertions

  • Cross-subtree exposure is blocked (404/empty, not the real data)
Open a member and suspend the account
J08 · Member management · J08-member-suspend · ui · 774ms
PASS
Agents manage member status (view-only KYC, no fraud surface).

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Members
  • Wait for the member grid
  • Open player Arun
  • Suspend the member
  • Wait for confirmation toast

Assertions

  • Member grid lists players in the subtree
  • KYC is shown read-only (external identity system)
  • Suspend action confirmed via toast
Search narrows the member grid
J08 · Member management · J08-member-search · ui · 678ms
PASS
Find a member by name/username.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Members
  • Search for "arun"
  • Wait for the filtered row

Assertions

  • Matching member remains after filtering
Only your own adjacent edge is settleable
J10 · Settlement · J10-adjacent-only · ui · 683ms
PASS
Cash settles parent↔child only; deeper edges are not actionable.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Settlement
  • Wait for the edge list

Assertions

  • Your own edge (Raj→Amit) has a "Mark settled" action
  • Deeper edges show "not your edge" (adjacent-only rule)
Settle an edge (offline cash) → confirmed balanced posting
J10 · Settlement · J10-settle-edge · ui · 2.2s
PASS
Marking an edge settled reduces its net via a confirmed posting.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Settlement
  • Mark the Raj→Amit edge settled
  • Confirm the settlement
  • Complete step-up authentication
  • Wait for confirmation

Assertions

  • Edge settlement confirmed
Reparenting a node with an unsettled edge is blocked
J11 · Reparent · J11-settlement-gated · ui · negative · 1.0s
PASS
Reparent is settlement-gated: the cut edge to the current parent must be net-zero.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Amit's node drawer
  • Wait for the drawer to load
  • Open Reparent and attempt to move the node
  • Observe the settlement-gated rejection

Assertions

  • Reparent blocked — the cut edge is not net-zero settled
Toggle a node's partnership (PT) — audited
J12 · PT toggle · J12-pt-toggle · ui · 1.0s
PASS
Partnership split can be toggled on a downline node; the change is audited.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Amit's drawer
  • Toggle partnership (PT)
  • Wait for confirmation toast

Assertions

  • PT / product-locks card is present
  • PT toggle confirmed (audited change)
Risk desk sees the rollback / re-settle tools
J13 · Rollback · J13-riskdesk-can · ui · 647ms
PASS
Only the risk desk can access rollback.

Steps

  • Log in as @riskdesk (password "demo") and pass MFA (code 123456)
  • Open Settlement as the risk desk

Assertions

  • Rollback / re-settle tab is available to the risk desk
A plain agent cannot roll back (hidden UI + 403 API)
J13 · Rollback · J13-agent-cannot · hybrid · negative · 646ms
PASS
Defense in depth: the tool is hidden and the API refuses.

Steps

  • Log in as @ag_ramesh (password "demo") and pass MFA (code 123456)
  • Open Settlement as a plain agent
  • Attempt the rollback API directly

Assertions

  • Rollback tab is NOT shown to a plain agent
  • Direct rollback API call is refused with 403
Analytics shows KPIs, hierarchy P&L, by-sport and top players
J14/J17 · Analytics · J14-analytics-sections · ui · 691ms
PASS
Rich reporting rolled up across the subtree.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Analytics
  • Switch the range to 30d

Assertions

  • Turnover KPI visible
  • Hierarchy P&L section visible
  • By-sport breakdown present
  • Top players panel present
  • Report still renders after changing range
A node without the analytics entitlement cannot see it
J14/J17 · Analytics · J14-entitlement-gate · ui · negative · 618ms
PASS
The client hides what the node may not do (server also enforces).

Steps

  • Log in as @sub_kiran (password "demo") and pass MFA (code 123456)

Assertions

  • Analytics nav item is absent for a non-entitled node
Security settings list MFA devices and posture
J15 · Security settings · J15-security · ui · 651ms
PASS
A user manages their own MFA devices.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Settings

Assertions

  • Multi-factor devices section is shown
  • Security posture is shown
Live surveillance feed streams new downline bets
J16 · Bet surveillance · J16-live-feed · ui · 6.7s
PASS
The upline watches live bet flow across the subtree; it updates in real time.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Bet Surveillance
  • Wait for the feed to populate
  • Watch the live feed for ~6s

Assertions

  • Bets are streaming for the subtree
  • New bets appended live (feed grew)
Filter the feed by sport and switch to History
J16 · Bet surveillance · J16-filters · ui · 2.2s
PASS
Rich filters let manual surveillance drill into events/markets/history.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Open Bet Surveillance
  • Filter by the Cricket sport
  • Switch to History mode
  • Let the historical query load

Assertions

  • Surveillance filter bar is present
  • Feed still renders under filters + history mode
Surveillance feed never leaks a sibling branch's bets
J16 · Bet surveillance · J16-rls-scope · api · negative · 603ms
PASS
RLS: an INR upline cannot see the POINT branch's players.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Fetch the surveillance feed

Assertions

  • Feed returned bets for the caller subtree
  • No bets from the sibling POINT branch appear (RLS)
RLS blocks reading a node outside the subtree
J00 · Cross-cutting · J00-rls-members · api · negative · 619ms
PASS
A member fetch outside the caller subtree returns nothing.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Request a POINT-tree member (outside subtree)

Assertions

  • Cross-subtree member read blocked (404/403/empty)
No fraud/AML case surface exists in the console
J00 · Cross-cutting · J00-no-fraud-surface · ui · 599ms
PASS
Activity monitoring is present; formal fraud/AML case management is not.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)

Assertions

  • No "Fraud" nav surface
  • No "AML" nav surface
  • No "Investigation / case" nav surface
Every money mutation is written to the audit log
J00 · Cross-cutting · J00-audit-logged · ui · 2.2s
PASS
A credit transfer appears in the append-only audit trail.

Steps

  • Log in as @sm_raj (password "demo") and pass MFA (code 123456)
  • Perform a give transfer
  • Open the Audit Log
  • Wait for the audit entries

Assertions

  • The credit transfer is recorded in the audit trail
Generated 2026-07-15 06:26:44 UTC · 118 steps · 65 assertions · videos are WebM (play in Chrome/Firefox/Edge). Self-contained: keep index.html next to the videos/ folder.