Home / Work / Kestrel Ops / Test report

Proof project · concept, not client work

Kestrel Ops test report

Every check below is an automated test that calls the real API and then verifies the database. Plain-English names first; the technical detail is there if you want it.

216 / 216Acceptance checks passed
5 / 5Daylight-saving checks passed
0Failed
9b65cc906bBuild tested · 1 Nov 2026

Environment: local Wrangler with Cloudflare D1 emulation, synthetic data. Concurrency tests inject a change between a read and a write to prove stale actions are refused; they are not production load tests. This is not a security certification.

Reconciliation checks

35 rules · green

Run on the seeded data and again after the scenarios. Each rule must hold for the books to be considered correct.

  • Every ledger transaction balances to zero
  • No client wallet is negative
  • Clearing account equals in-flight withdrawals
  • Each withdrawal's reservation matches its status
  • Each settled withdrawal has exactly one payment evidence (provider success or adjudication) for its amount
  • Each settled withdrawal has a settlement entry for its exact amount
  • Each payment confirmed after a reversal has one adjudication and a recovery entry for its amount
  • No unsettled withdrawal carries settlement evidence
  • Each partner's wallet matches its commission records, trade by trade
  • Commission expense equals commission records
  • Every commission line matches the agreement in force at trade close (payee, level, rate, rounding)
  • Every processed trade pays exactly the partners entitled to it (attribution, tree at that version, lots, agreement)
  • Cancelled trades net to zero commission
  • No trade paid twice at the same level
  • Partner tree has no loops
  • No unresolved conflicting provider events
  • No orphaned provider events
  • Every received payment is posted exactly once for its received amount
  • Unmatched money sits in suspense; matched money has left it
  • Restricted deposits are held; available deposits were credited to the wallet once
  • Each deposit instruction's paid amount equals the payments matched to it
  • Refunds and chargebacks each stay within the payment, and refund records match
  • Each chargeback's postings match its record (provider, wallet, receivable, fee)
  • No conflicting payment events waiting for review
  • Funds reserved for transfers equal transfers not yet final
  • Each trading account's platform balance equals the transfers the CRM confirmed
  • No transfer with an unknown outcome
  • Every received payment event has been applied (no pending or rejected chargebacks)
  • Every open chargeback on an allocated payment names that payment's client
  • No trading account is overdrawn on the platform or below its margin in use
  • Each transfer's status matches its single platform outcome (applied or cancelled)
  • Each conversion links to one existing client, and no client is linked to two active leads
  • Every lead is owned by active sales staff (or unassigned) and matches its latest assignment history
  • Every unresolved provider report has an open case, and every open case still has unresolved work
  • No unresolved success reports waiting for review

Withdrawals and approvals

59 / 59 passed

Maker-checker, second approvals, stale versions, overdraw and duplicate-send protection.

  • ✓

    Start demo signs in as Finance Officer (Omar)

  • ✓

    Seed data reconciles

  • ✓

    1 Maker cannot approve own withdrawal

    Technical detailMaker-checker rule: you created or changed this withdrawal, so you cannot approve it.
  • ✓

    1b Denied attempt is in the audit log

  • ✓

    2 Support cannot approve

  • ✓

    3 Admin cannot approve (segregation of duties)

  • ✓

    4 Approval for stale version rejected

  • ✓

    4b No approval stored

  • ✓

    Checker (Grace) approves

    Technical detail{"ok":true,"status":"approved","required":1}
  • ✓

    5 Edit after approval → back to pending, version 2

  • ✓

    5b Old approval invalidated

  • ✓

    5c Ledger re-reserved and reconciles

  • ✓

    5d Cannot send after change without new approval

  • ✓

    5e Grace can re-approve v2 (she did not edit it)

  • ✓

    6 First approval on $12,500 keeps it pending

  • ✓

    6b Same approver twice denied

  • ✓

    6c Second independent approver completes approval

  • ✓

    7 Send with duplicate callback

    Technical detail{"ok":true,"outcome":"success","attempt":1,"callback":"settled","duplicate":"duplicate_ignored"}
  • ✓

    7b Exactly one settlement debit

  • ✓

    8 Failed payout enters exception queue

  • ✓

    8b Retry succeeds → settled

  • ✓

    8c Reverse returns funds to wallet

  • ✓

    9 Concurrent double-approve stores one approval

    Technical detail200/409
  • ✓

    9b Concurrent double-send pays out once

    Technical detail200/409
  • ✓

    10 Overdraw attempt denied ($2,000 from a $1,500 wallet)

    Technical detailInsufficient available balance for this withdrawal.
  • ✓

    11 Workspace B sees its own fresh data (WD-1002 still pending)

  • ✓

    11b Workspace B cannot touch workspace A's new withdrawal

  • ✓

    12 POST with wrong CSRF token rejected

  • ✓

    12b Old session revoked after switch

  • ✓

    Compliance releases hold with note

  • ✓

    14 Reconciliation green after all scenarios

  • ✓

    Audit CSV export works

  • ✓

    R1 Concurrent edits cannot overdraw: exactly one succeeds

    Technical detail200/409
  • ✓

    R1b Wallet never negative after edit race

    Technical detail$3550.00
  • ✓

    R2 Edit/create race leaves wallet non-negative

    Technical detail200/409 wallet $710.00
  • ✓

    R3 Support cannot simulate client requests (no reservation)

  • ✓

    R4 Concurrent creates get distinct references

    Technical detailWD-1009 / WD-1010
  • ✓

    R4b Retried create with the same request_id returns the original

    Technical detailWD-1011 / WD-1011
  • ✓

    R5 Injected failure: send committed, event rolled back, outcome reported as uncertain

    Technical detail500 sent events=0
  • ✓

    R5b Replay settles exactly once

  • ✓

    R6 Late success for attempt 1 does not settle attempt 2

    Technical detailunmatched_needs_review sent
  • ✓

    R6b Reconciliation flags the unapplied success for review

  • ✓

    R6c With two success reports open (possible double payout), attempt 2 is also held for review

    Technical detailunmatched_needs_review
  • ✓

    R6c2 Compliance resolves both reports; withdrawal settles exactly once

  • ✓

    R6d Callback with wrong amount is not applied

    Technical detailstale_ignored
  • ✓

    R7 KYC change auto-holds the approved withdrawal and voids approvals

    Technical detailon_hold
  • ✓

    R7b Send is refused while KYC is not current

  • ✓

    R7c A hold release cannot waive KYC

  • ✓

    R7d After KYC renewal, review and fresh approval, payout succeeds

  • ✓

    R8 Reassigned confirmation turns reconciliation red with specific findings

    Technical detailMissing or conflicting: WD-1001 | WD-1002
  • ✓

    R9 Database rejects UPDATE and DELETE on audit

    Technical detail{"audit_update":"blocked","audit_delete":"blocked","ledger_update":"blocked","ledger_delete":"blocked"}
  • ✓

    R9b Database rejects UPDATE and DELETE on ledger

  • ✓

    B1 Beneficiary changes between validation and commit: nothing is sent

    Technical detail409 approved
  • ✓

    B1b The changed instructions need fresh approval before sending

    Technical detail403
  • ✓

    D1 Impossible calendar dates are refused

    Technical detail{"error":"That date does not exist. Choose a real calendar date."}
  • ✓

    R1 Every failing check carries a stable id and its own items (unbalanced ledger links to the withdrawal with a next step)

    Technical detailledger_balanced:1,case_consistency:4,pe_unmatched:5
  • ✓

    R1b No reconciliation advice tells the operator to void and re-run

  • ✓

    AP1 After my first of two approvals the item leaves my 'Needs my approval' list but stays for the other checker

    Technical detailtrue/false/true
  • ✓

    R1 Support cannot move funds, refund or create deposit instructions

Payment provider outcomes and investigations

72 / 72 passed

Late, duplicate, conflicting and wrong-amount provider reports; cases opened and closed safely.

  • ✓

    X1 Late success after failure is held for review

  • ✓

    X1b Retry is refused while a success report is unresolved

    Technical detail403
  • ✓

    X1c Only Compliance can resolve provider events

  • ✓

    X1d Confirmed-paid resolution settles once with an audit record

  • ✓

    X2 Same callback ID with different content is flagged as a conflict, not a duplicate

    Technical detailconflict_needs_review
  • ✓

    X2b Reversal blocked while the conflict is unresolved

  • ✓

    X2c Retry blocked while the conflict is unresolved

  • ✓

    X2d Reconciliation shows the open conflict

  • ✓

    X2e After a recorded 'not paid' decision, reversal proceeds

  • ✓

    X2f Reconciliation green after both investigations

  • ✓

    X3 Same request key with a different amount is refused

    Technical detail200/409
  • ✓

    X3b Invalid request key is rejected, not ignored

  • ✓

    C1a Conflict recorded first: reversal refused, withdrawal stays in exception

    Technical detailconflict_needs_review/409 → exception
  • ✓

    C1b Late report after a committed reversal: reversal kept in history, open recovery case recorded

    Technical detail200/conflict_needs_review → reversed
  • ✓

    C1c New withdrawals for that client are paused while the recovery case is open

    Technical detail409
  • ✓

    C1d Reconciliation flags the open post-reversal case

  • ✓

    C1e Authorized recovery: status 'paid after reversal', reversal credit recovered, adjudication stored

    Technical detail{"ok":true,"decision":"paid","resolution":"confirmed_paid_after_reversal"}
  • ✓

    C1f Reconciliation green after the recovery

    Technical detailNo unresolved conflicting provider events: Same event ID, different content: cb_w_268696067c714ed9_1 → WD-1006
  • ✓

    C2 Two concurrent investigation decisions: exactly one commits

    Technical detail200/409
  • ✓

    C3 Conflict confirmed paid: settled once, original messages preserved

  • ✓

    C3b Reconciliation green with adjudicated settlements

  • ✓

    C4 Opposing concurrent moves: one fails cleanly, no loop

    Technical detail200/409
  • ✓

    C5 Agreement effective today is refused (would touch same-day trades)

  • ✓

    C6 A zero-rounded commission is recorded and does not strand later trades

    Technical detail{"ok":true,"processed":2,"rows":5,"amount":1075}
  • ✓

    C6b Reconciliation green after zero-value commission

  • ✓

    C7 Misallocated partner balance turns reconciliation red with the partner named

  • ✓

    V1 $1 reported against $300: a $1 verification is refused, and $300 needs an evidenced override

    Technical detail422/422
  • ✓

    V1b With evidence the override is recorded: expected, reported and verified amounts kept

  • ✓

    V1c A decided case cannot be decided again

  • ✓

    E0 Reconciliation green before the payee fixture

  • ✓

    E1 Wrong payee with valid rate and balanced ledger is detected by entitlement rebuild

    Technical detail1 trade(s): T-5043: expected ib_atlas L1; found unexpected ib_nova L1
  • ✓

    E1b Wallet-vs-records check alone would not catch it (records agree)

  • ✓

    K1 Identical conflicting report delivered twice: one investigation case

    Technical detailconflict_needs_review/conflict_duplicate_ignored cases 1
  • ✓

    P1 While the recovery case is open, an already-approved payout for the same client is blocked

    Technical detail409
  • ✓

    P1b Increases are blocked too

    Technical detail409
  • ✓

    K2 Same report after the decision: refers to the decision, no new case, no second financial effect

    Technical detailconflict_already_decided cases 1
  • ✓

    P1c After the decision, the paused payout can go

    Technical detail200
  • ✓

    I1 A report that needs a decision opens a case automatically with a 24-hour deadline

  • ✓

    I1b Reconciliation exception links straight to the withdrawal with the difference and next step

    Technical detail{"label":"WD-1006 · cb_case_n1","href":"#/withdrawal/w_1a966622c9d04ccf","diff":"Provider reported $275.00 paid; withdrawal is $275.00","next":"Compliance records what the bank or provider statement shows (Investigations)."}
  • ✓

    I2 Support can add an internal note but cannot take the case

    Technical detail200/403
  • ✓

    I3 Compliance takes the case, records structured evidence and escalation (deadline within 4h)

  • ✓

    I3b Evidence without a source and reference is refused

  • ✓

    I4 The decision closes the case and is kept in its history; queue moves it to Closed

  • ✓

    I5 A closed case cannot be changed

  • ✓

    M1 Two distinct conflicting reports open two decisions

    Technical detail2
  • ✓

    M1b After the first decision the second report keeps all client payouts paused

    Technical detail200/409
  • ✓

    M1c Second report: 'paid again' refused, wrong reference refused, linked to the confirmed payment with no second effect

    Technical detail409/400/200
  • ✓

    M1d Only after every report is decided do payouts resume; reconciliation green

    Technical detail200
  • ✓

    DB1 Dashboard 'Paid out' includes the payment confirmed after reversal

    Technical detail{"paid0":180000,"paid1":{"settled":190000,"after_reversal":30000,"total":220000}}
  • ✓

    CA-note Case closes between read and write: 409, no history entry, no successful audit row

    Technical detail409 entries=opened okAudit=0
  • ✓

    CA-evidence Case closes between read and write: 409, no history entry, no successful audit row

    Technical detail409 entries=opened okAudit=0
  • ✓

    CA-assign Case closes between read and write: 409, no history entry, no successful audit row

    Technical detail409 entries=opened okAudit=0
  • ✓

    CA-escalate Case closes between read and write: 409, no history entry, no successful audit row

    Technical detail409 entries=opened okAudit=0
  • ✓

    CL1 Case creation fails → the report is rolled back too; the replay records report and case together

    Technical detail500 unmatched_needs_review
  • ✓

    CL3 A second report while the case is open is added to the same case

  • ✓

    CL2 Closing fails → the decision is rolled back too; the retry decides and closes exactly once

    Technical detail500/200
  • ✓

    H1 A new report opens a second case; both cases keep their own history and stay reachable

  • ✓

    CL4 Case consistency check: the normal lifecycle (WD-1010) is consistent, and the four cases force-closed by the race hook are flagged as reports without a case

    Technical detail["WD-1006:Unresolved provider report without an open case","WD-1007:Unresolved provider report without an open case","WD-1008:Unresolved provider report without an open case","WD-1009:Unresolved provider report without an open case"]
  • ✓

    SC1 A dialog prepared for case A (now closed) is refused after case B opens; neither history changes

    Technical detail409 [1,3]
  • ✓

    SC2 Missing case id, missing/null/string version refused (400), stale version refused (409), a fresh submission for case B succeeds; refused requests leave no history

    Technical detail400/409/200
  • ✓

    E2 Every entitlement failure branch returns its own item with link, difference and next step (no inputs, attribution, lots, chain)

    Technical detail["QA-MIRROR-914224:1 reversal line(s) vs 1 accrual line(s),","QA-NOCALC-392333:Marked processed, but the inputs used to","QA-ATTR-589415:Calculated for partner ib_nova; the clie","QA-ATTR-589415:Expected ib_nova L1 $7.00","QA-LOTS-238029:Calculated on 2.000 lots; the trade has ","QA-LOTS-238029:Expected ib_atlas L1 $9.00","QA-CHAIN-832673:Recorded chain ib_atlas → ib_nova; the t","QA-CHAIN-832673:Expected ib_atlas L1 $9.00"]
  • ✓

    C1 Chargeback after funds left the wallet: wallet debited to zero, shortfall recorded as receivable, client restricted

    Technical detailchargeback_recorded wallet=0 recv=-79900
  • ✓

    C1b While the chargeback is open, transfers and withdrawals for the client are refused

    Technical detail409/409
  • ✓

    C2 Chargeback won: one compensating posting restores wallet and receivable; a repeated close changes nothing

    Technical detailchargeback_won/already_closed_ignored
  • ✓

    C3 A bank-forced chargeback after a refund is recorded (the provider takes it) and flagged as overlapping the refund; the client owes the shortfall

    Technical detail200 chargeback_recorded
  • ✓

    C3b A further chargeback beyond what is left on the payment is not applied; it is recorded as rejected for review

    Technical detailrejected_exceeds_payment
  • ✓

    H1 A close naming a different payment cannot resolve the dispute: kept as a conflict, dispute open, wallet and audit unchanged

    Technical detailconflict_needs_review open
  • ✓

    H1b A repeated 'opened' with the same dispute id but different content is a conflict; identical content is a duplicate; nothing is posted twice

    Technical detailconflict_needs_review/duplicate_dispute_ignored
  • ✓

    H1c The genuine close for the right payment still applies

    Technical detailchargeback_won
  • ✓

    H2 Dispute ids that look alike under SQL wildcards (dp_a, dpXa): exactly two chargeback rows totalling $20, no false reconciliation failure

    Technical detail2 rows 2000
  • ✓

    H2b Regression workspace reconciles except the deliberately conflicting events from H1/H1b

    Technical detailfund_conflicts
  • ✓

    H3 Funding report counts a payment confirmed after reversal once, as an external withdrawal (same classification as the dashboard)

    Technical detailreport 224500 vs dashboard 224500 (after reversal 21500)

Deposits, refunds and chargebacks

12 / 12 passed

Instructions, matching, restricted funds, refunds, chargebacks and fees.

  • ✓

    F1 Payment matching the instruction is credited once for the received amount; fee booked separately

    Technical detailcredited_available
  • ✓

    F2 Same event q_again, a new event id for the same payment, and a changed amount: never a second credit

    Technical detailduplicate_event_ignored/same_payment_already_recorded/conflict_needs_review
  • ✓

    F2b Reconciliation flags the conflicting payment event with a drill-down

  • ✓

    F3 Partial payments: two receipts complete one instruction; the overpayment waits in suspense instead of being allocated twice

    Technical detailcredited_available/held_in_suspense/credited_available paid=100000
  • ✓

    F4 Suspense allocation needs a second person; it moves out of suspense exactly once

    Technical detail403/200/409
  • ✓

    F5 KYC not current: payment is recorded but held as restricted, not added to the usable wallet

    Technical detailcredited_restricted
  • ✓

    F5b Release is refused while KYC is not current (checked inside the transaction)

  • ✓

    F5c KYC expires between the check and the credit: nothing is released

    Technical detail409
  • ✓

    F5d After KYC approval the restricted funds are released once

    Technical detail200
  • ✓

    F6 Two concurrent refunds that together exceed the payment: exactly one applies

    Technical detail200/409
  • ✓

    F9 After the whole journey, reconciliation is green except the deliberately conflicting event and the rejected over-limit chargeback

    Technical detailfund_conflicts: 1 conflicting event(s) | fund_pending: 1 event(s) not applied
  • ✓

    F10 Funding report: published formula, internal transfers excluded, totals traceable to lines

Trading-account transfers

15 / 15 passed

Wallet to trading account and back, with unknown outcomes and concurrent requests.

  • ✓

    G1 Two concurrent $80 transfers back from a $100 trading account: exactly one succeeds, the account is never overdrawn

    Technical detail200:confirmed / 409:Transfer refused: free margin on 5101207 is $20.00 (balance $20.00, margin in use $0.00). plat=2000
  • ✓

    G1b With the early check skipped, the platform itself refuses a debit beyond free margin in the same statement; reconciliation checks platform validity

    Technical detailfailed plat=2000
  • ✓

    G2 Platform applied, response lost, retry answered 'reject': the applied outcome wins; confirmed, funds stay on the platform, nothing returned to the wallet

    Technical detailconfirmed wallet=-10000
  • ✓

    G3 A retry lands on the platform just before a release: the release is refused and the transfer is confirmed, never both

    Technical detail409/confirmed
  • ✓

    G3b Concurrent retry and release of the same operation: exactly one authoritative outcome (applied+confirmed or cancelled+released)

    Technical detail200/409 → confirmed
  • ✓

    G4 After a chargeback opens, a retry that could create a new platform effect is refused; checking the platform is still allowed

    Technical detail409 Retry blocked: open chargeback. A retry could apply a new movement on the platform. You can still check the platform; release the reserved funds once the platform confirms cancellation.
  • ✓

    G4b KYC expires between reservation and dispatch: the platform call is refused, the operation is cancelled and the reservation returned

    Technical detailfailed
  • ✓

    G5 Chargeback before its payment stays pending (flagged, replay retries instead of ignoring) and applies when the payment arrives

    Technical detailpending_payment_not_received/pending_payment_not_received/duplicate_event_ignored
  • ✓

    G6 Wallet emptied concurrently with a chargeback: recovery and shortfall are computed inside the transaction; the chargeback still applies and restricts the client

    Technical detailchargeback_recorded 0/30000
  • ✓

    G7 'Closed' arriving before 'opened' stays pending, then applies right after the dispute is recorded

    Technical detailpending_dispute_not_open → won
  • ✓

    G8 Suspense → chargeback → allocation to c7: the open chargeback restricts c7 at once; when won, $50 returns to client:c7 (never client:null)

    Technical detailchargeback_won won_to=client:c7 Δ=10000
  • ✓

    G8b Same path to a restricted client (lost): the hold keeps only the allocated part, the chargeback names c4, and the database rejects postings to a non-existent client account

    Technical detailchargeback_lost hold=6000 sql=rejected
  • ✓

    G9 A rejection interleaved before the approval batch: approval fails and the instruction is NOT marked paid (claim first, everything else conditional)

    Technical detail409 paid=0 open
  • ✓

    G10 Report by posting date: a chargeback stays in its period after it is later won; the recovery appears in the period it was posted

    Technical detailp1={"gross_deposits":50000,"refunds":0,"chargebacks":20000,"chargeback_recoveries":0,"external_withdrawals":0,"fees":1500,"internal_to_accounts":0,"internal_from_accounts":0,"net_external_funding":30000} p2 rec=20000
  • ✓

    G11 Reconciliation of the regression workspace is green after all reproductions (detection is not the only control: each case was prevented)

Partner commissions

26 / 26 passed

Agreement versions, partner trees, rounding and voided trades.

  • ✓

    IB1 Seeded trades processed on start (no unprocessed left)

  • ✓

    IB2 Re-running the calculation pays nothing twice

  • ✓

    IB3 Every Atlas statement line reproduces from agreement, level and rounding

    Technical detail28/28
  • ✓

    IB3b Atlas level-1 lines use v1 or v2 depending on trade close date

  • ✓

    IB4 A level-3 client pays three partners (L1 Coastal, L2 Brightline, L3 Atlas)

    Technical detailib_coast:L1,ib_bright:L2,ib_atlas:L3
  • ✓

    IB5 Support cannot run commissions

  • ✓

    IB6 Moving a partner under its own sub-partner is refused (cycle)

  • ✓

    IB7 Backdated agreement refused

  • ✓

    IB8 New agreement version leaves past statement lines unchanged

    Technical detail{"ok":true,"version":2}
  • ✓

    IB9 Cancelling a trade reverses its commissions

  • ✓

    IB9b Cancelling twice is refused

  • ✓

    IB10 Concurrent calculation runs process each new trade once

    Technical detail4+0
  • ✓

    IB10b Reconciliation green including IB checks

  • ✓

    T1 Partner move right after the snapshot: the trade is not paid on a mixed tree, run reports the interruption

    Technical detail{"ok":true,"processed":0,"rows":0,"amount":0,"stopped":"Partner tree changed during the run; remaining trades will use the new tree on the next run."} |
  • ✓

    T1b Next run pays the new chain (Brightline → Nova) and entitlement reconciles

    Technical detail{"ok":true,"processed":1,"rows":2,"amount":750} |
  • ✓

    Z1 Voiding a trade with mixed $0.00 and non-zero commissions keeps reconciliation green

    Technical detail{"ok":true,"reversed":2,"ledger_lines":1} |
  • ✓

    T1 Transfer to a trading account: reserved, applied once on the platform, confirmed

    Technical detail{"ok":true,"id":"tf_58135cf2a626442b","status":"confirmed"}
  • ✓

    T2 Platform credits but the response is lost: transfer is 'uncertain', funds stay reserved, nothing is refunded

    Technical detailuncertain
  • ✓

    T2b Reconciliation shows the uncertain transfer and the platform/CRM difference with drill-down

  • ✓

    T3 Retry of an operation the platform already applied: confirmed without a second platform effect, even if the platform now answers 'reject'

    Technical detailconfirmed plat=100000
  • ✓

    T4 Releasing funds is refused when the platform shows the operation; the transfer can only be confirmed

    Technical detail409/409
  • ✓

    T5 Platform rejects: transfer failed and funds return to the wallet

    Technical detailfailed
  • ✓

    T6 Timeout without effect: the check finds nothing; release with a recorded confirmation returns the funds

    Technical detailfalse/failed
  • ✓

    T7 Transfer back is limited by the platform's free margin; a covered amount returns to the wallet

    Technical detail409/confirmed
  • ✓

    T8 Demo accounts cannot receive real funds

  • ✓

    T9 Two concurrent transfers that together exceed the wallet: exactly one reserves funds

    Technical detail200/409

Sales CRM

32 / 32 passed

Row access, duplicates, contact rules, opt-outs, merges, exports and first-deposit reporting.

  • ✓

    S1 Agent sees only their own book; another agent's lead is 'not found'; client money, dashboard, ledger/lead exports and transfers are refused

    Technical detail5/404/403/403/403/403/403
  • ✓

    S1b Only the explicit export role (Operations Admin) can export leads: fixed columns without email/phone, audited with scope, columns and row count (no personal data in the audit)

    Technical detail200
  • ✓

    S2 Versioned assignment rules: Arabic → Arabic desk (rule r1 v1); no matching rule or missing country/language → unassigned queue with the reason; a disabled owner is skipped (unassigned)

    Technical detailRule r1 v1 (language = ar) | No rule matched (language it, country IT): unassigned queue | Matching rule's owner is disabled: unassigned queue
  • ✓

    S3 Duplicate review proposes, never decides: same email (case-insensitive) + same E.164 phone = strong; a phone without country context is not matched; agents outside both leads never see the item

    Technical detailSame email · Same phone / 0 / sara sees=false
  • ✓

    S4 Reviewed merge: proposer cannot approve; survivor keeps both histories, the most restrictive preference (do-not-contact) survives, and the alias's queued message is cancelled

    Technical detail200/403/200 dnc=1
  • ✓

    S4b Merge approval is bound to both lead versions: a lead that changed after the proposal makes approval fail (nothing merged)

    Technical detail409
  • ✓

    S5 Concurrent assignment: exactly one applies; history is append-only; non-sales staff cannot own leads; an agent disabled between selection and assignment is refused

    Technical detail200/409 rejected 409:That agent is disabled or not sales staff. Choose an active agent. 409:That agent is disabled or not sales staff. Choose an active agent. last=[null,"u_sara"] owner=u_sara
  • ✓

    S6 Reassignment revokes the former agent's access on the next request (lead and its follow-up), and open follow-ups move to the new owner

    Technical detail404/404 owner=u_sara
  • ✓

    S7 'Contacted' means an actual two-way interaction: an unanswered call leaves the stage at new; a reached call sets contacted; a manual 'contacted' edit is refused

    Technical detailnew → contacted / 400
  • ✓

    S8 History is never hidden: a contact that happened outside policy (do-not-contact) is recorded and flagged (activity + flagged audit), not refused

    Technical detail200
  • ✓

    S9 Outbound requests: blocked at request when suppressed; a dispatch timeout retried with the same key never duplicates; delivery is shown as simulated, never 'sent'

    Technical detailblocked/504/true/simulated_delivered
  • ✓

    S9b Second check at dispatch: an SMS scheduled before the opt-out is blocked at dispatch; a call requested by the former owner is cancelled after reassignment

    Technical detailblocked/cancelled
  • ✓

    S9c Quiet hours use the lead's IANA time zone across the DST change (13:30 UTC = 09:30 EDT allowed; next day 13:30 UTC = 08:30 EST deferred); unknown time zone defers calls for review

    Technical detaildeferred/simulated_delivered/deferred
  • ✓

    S10 Conversion: refused while a duplicate review is open; a double-click with the same request id creates exactly one client (KYC pending, money restricted)

    Technical detail409/200/200 created
  • ✓

    S10b Response lost after commit: retry with the same request id returns the same client; only a team lead may link an existing client, and one client cannot be linked to two leads

    Technical detail504/200/403/200/409
  • ✓

    S11 FTD follows the published rule (ftd-v1) from ledger postings: date, amount and receipt recorded; after a full chargeback the FTD stays, a reversal indicator appears, net funding is $0 and the sales stage is untouched

    Technical detailtrue/chargeback/historically_qualified/qualified
  • ✓

    S12 Reassignment after the FTD does not move historical credit: the activity report credits the FTD to the owner at that moment (Sara), not the new owner (Karim); agents see only their own credit

    Technical detailnina sara=1 karim=0 sara=1
  • ✓

    S12b Two report views with defined denominators: the cohort view publishes a conversion rate (cohort converted ÷ cohort leads) with an as-of date; the activity view has no conversion rate

    Technical detail33.3%
  • ✓

    S13 A restricted deposit (KYC pending) does not count as FTD; it qualifies when the funds are released into the usable wallet

    Technical detailcredited_restricted → FTD
  • ✓

    S14 Reconciliation includes the sales checks (one client per active lead, ownership vs history incl. active owners) and the sales workspace reconciles after the whole journey

  • ✓

    J1 End-to-end Sales journey (one workspace): lead twice → duplicate reviewed → assigned → follow-up → opt-out blocks dispatch → convert without KYC bypass → FTD → chargeback → reassignment keeps credit and revokes access

    Technical detail✓ 1 Lead arrives twice → one strong duplicate item, nothing merged automatically (Same email · Same phone) | ✓ 2 Duplicate reviewed: agent proposes, team lead approves; the repeat becomes an alias (200/200) | ✓ 3 Agent assigned by versioned rule (English desk → Sara), recorded in append-only history (Rule r4 v1 (language = en)) | ✓ 4 Follow-up scheduled; a reached call sets 'contacted', then the agent qualifies the lead (qualified) | ✓ 5 Opt-out after scheduling blocks the queued SMS at dispatch (second check) (queued → blocked) | ✓ 6 Lead converts without bypassing KYC: client created with KYC pending, transfers blocked, agent gets no client-money access (pending/403) | ✓ 7 Compliance approves KYC; the qualifying deposit records the FTD from the ledger (rule ftd-v1) (credited_available / net_funded) | ✓ 8 Chargeback changes net funding without erasing history: FTD kept with a reversal flag, net $0, stage unchanged, both postings still in the ledger (chargeback/0/qualified/ledger rows=2) | ✓ 9 Reassignment keeps historical credit and revokes old access: Sara keeps the conversion + FTD credit, loses the lead and its task on the next request; the task moves to Karim (404/404 credit=u_sara) | ✓ 10 The workspace reconciles after the whole journey
  • ✓

    R1 Replaying an outbound key after reassignment discloses nothing to the former owner (404, no destination); a changed payload on the same key is refused (409); an over-long key is rejected, never truncated

    Technical detail404/409/400
  • ✓

    R2 A delivery is never claimed after the state changed between check and claim: opt-out → blocked, reassignment → cancelled, requester disabled → cancelled, destination changed → cancelled

    Technical detailblocked:Blocked at dispatch: lead asked not to be contacted | cancelled:Lead was reassigned before dispatch; the new owner must request contact again | cancelled:Requester is no longer active | cancelled:Destination changed since the request (e.g. after a merge); request again
  • ✓

    R3 Reassignment that wins before the commit rejects the old owner's note and new follow-up: 409, no activity row, no task, denied audit only

    Technical detail409/409 tasks=0
  • ✓

    R4 An opt-out recorded on a merged alias protects the surviving lead (DNC on the survivor, provenance names the alias); lifting through the alias is refused

    Technical detail200/1/409
  • ✓

    R5 Two successive merges (A→B→C): the final survivor shows the first alias's history and keeps the most restrictive preference

    Technical detail200 dnc=1
  • ✓

    R6 Sales CSV export neutralises formula prefixes and leading control characters (=, +, -, @, leading space or tab)

    Technical detail'=1+1 ¦ '@cmd ¦ '=HYPERLINK(""x"") ¦ '=1
  • ✓

    R7a Restricted deposit → partial refund → release: the FTD is the qualifying release posting ($200), not the original receipt amount ($300)

    Technical detail200/200 ftd=20000 deposit_release
  • ✓

    R7b Historical as-of view: a chargeback posted later does not appear in an earlier as-of result (no reversal, net $200); after it, the reversal shows and the FTD is unchanged

    Technical detailbefore=null/20000 after=chargeback
  • ✓

    R9 Quiet hours or time zone changed between the policy read and the claim: the claim is refused and the fresh decision defers the SMS (no delivered activity), for both a new quiet window and an unknown time zone

    Technical detaildeferred:Deferred: quiet hours (12:00 Europe/London); allowed 15:00–12:00 local | deferred:Deferred: lead's time zone unknown; review before calling or texting
  • ✓

    R10 Opt-out on alias A while its survivor B is merged into C: the restriction lands on the current survivor C (or the request is refused); never a success that leaves C contactable

    Technical detail200 applied_to=C C.dnc=1
  • ✓

    R8 The review workspace still reconciles after all race and merge scenarios

Daylight-saving time

5 / 5 passed

Report date ranges on 23- and 25-hour days (TZ=Asia/Karachi run).

  • ✓

    DST1 Fall-back day (1 Nov 2026, 25 h): 11:30 PM that day is included

  • ✓

    DST1b 12:30 AM next day is excluded

  • ✓

    DST2 Spring-forward day (14 Mar 2027, 23 h): 12:30 AM on 15 Mar is excluded

  • ✓

    DST2b 11:30 PM on 14 Mar is included

  • ✓

    DST3 From boundary is local midnight

API SHA-256 prefix 4e198ce10c22 · Raw test output (plain text) · Back to the case study

Need software tested like this?

Book a free call →