SRS: UC_4.15.2 — Hard Breach: Level Stop (LIVE)
UC_4.15.2: Hard Breach — Level Stop (LIVE)
| Field | Value |
|---|---|
| BA in Charge | Huyen Dinh |
| Date Created | 2026-08-18 |
| Version | v6 |
| Document References | RFQ_ Stack Trading Prop Tech V7.pdf (§Hard Breach — Level Stop, §Appendix A/B, §Outbound Webhook EventsLEVEL_STOP_BREACH) · Zapier Integration V7.pdf (§Flow 7 full, §Flow 7B Path B, §Flow 9, §Flow 19, §Flow 20, §Table A/B, §Table C, §Table J) · QnA_STAGE2_FAILURE_AND_RECOVERY.md (FR-05/06/08/10-12 Flow 7 steps) · CR-20260816-001 · QnA_init_docs.md (UC_4.15.2, 6 items) |
Architecture note: LIVE Hard Breach shares the same Atomic Kill Switch mechanism, Frosted Glass display rule, and dynamic
Discount_Code_Duration_Dayswindow as SIM Hard Breach — UC_4.10.2. Three confirmed divergences are written out in full for LIVE:
- Trigger — LIVE uses
Market_Loss_When_Stopped(Table A/B per-level lookup), not SIM's flat 7.5% × Notional.- Recovery path — LIVE has no "Reset" option, only "Re-Buy" — every LIVE failure requires purchasing a brand-new evaluation.
Flow 7 vs. Flow 7B — do not conflate (v2 correction): Flow 7 (
Financial Reporting / Recycling Logic) is the master termination pipeline this UC owns end-to-end — Defense Gate → Refund Check → Ledger Close → Liquidation → Balance Check → Retention Gate (→ Flow 9) → Post-Termination Access Control → Digital Eviction → GL Posting → Notification → Feedback Survey Gate. Flow 7B (Retention & Retargeting) is a separate, independently-triggered Zapier flow — it fires off theStatusstate-change itself (not a call from inside Flow 7), runs a 1-hour cool-down + purchase check, then routes to Path A (SIM) or Path B (Live/Funded — in scope for this UC) to email a Klaviyo retention offer.
Document References
| # | Original Document | Key Sections Used |
|---|---|---|
| 1 | RFQ_ Stack Trading Prop Tech V7.pdf | §Hard Breach — Level Stop (Definition, Founding Mentor Edge Cases); §Appendix A (Table A) / Appendix B (Table B) —Market_Loss_When_Stopped, Severance_Pay; §Outbound Webhook Events (LEVEL_STOP_BREACH → "Triggers Flow 7 (Termination) or Flow 4B (Defense)") |
| 2 | Zapier Integration V7.pdf | §Flow 7 — Financial Reporting (Recycling Logic), full 11-step flow (Defense Gate, Refund Check, Ledger Close, Liquidation, Balance Check, Retention Gate, Post-Termination Access Control, Community/Digital Eviction, GL Posting, Notification, Feedback Survey Gate); §Flow 7B — Retention & Retargeting (Path B only, Live/Funded); §Flow 9 (Severance Protocol); §Flow 19 (Stagnation Monitor — alternate Flow 7 entry point); §Flow 20 (Trader Resignation Handler — alternate Flow 7 entry point); §Table C (Discount_Code_Duration_Days); §Table J (Pricing) |
| 3 | QnA_STAGE2_FAILURE_AND_RECOVERY.md | FR-05 (Balance Check → internal Slack, not Freshdesk;Bad_Debt_Log fields), FR-06 (virtual_equity lifecycle), FR-08 (GL Posting payload), FR-10/11/12 (Typeform survey — natively hosted, combined with Step 10 email, no Pod_Leader_Registry routing), FR-13 (Status = Terminated), FR-16 (Live Re-Buy pricing), FR-17 (is_professional universal flag), FR-18/19/26 (Severance eligibility/deduction), FR-29/52 (Stagnation email collision), FR-30 (Severance level threshold), FR-31/54 (D=0/Archival lifecycle for LIVE) |
| 4 | QnA_init_docs.md (UC_4.15.2) | QN-4.15.2-01 through -06 — all BA-confirmed |
| 5 | CR-20260816-001 | Stagnation Path — Double Notification Collision (Flow 19 → Flow 7 Step 10 suppression gate; confirmed NOT to affect Flow 7B) |
1. Overview
| Field | Content |
|---|---|
| ID | UC_4.15.2 |
| Use Case | Hard Breach — Level Stop (LIVE) |
| Description | When a Live trader'sNet_P&L drops to or below −Market_Loss_When_Stopped (per-level threshold, Table A/B), the system triggers the same Atomic Kill Switch as SIM: (1) lock order entry, (2) flatten all positions, (3) cancel all working orders, (4) update DB Status to 'Terminated'. The Dashboard freezes and renders the permanent "Frosted Glass" Failure Modal — but unlike SIM, the trading sub-account is hard-deleted immediately, and the only recovery path is Re-Buy (a brand-new evaluation), never a Reset. |
| Zapier Flow | Flow 7 (Financial Reporting/Recycling Logic — full termination pipeline, owned end-to-end by this UC) · Flow 7B Path B (Live/Funded retention → Klaviyo, separate flow triggered downstream by theStatus change) · Flow 9 (Severance Protocol, if Severance_Pay > 0) · Flow 19 (Stagnation Monitor) and Flow 20 (Resignation Handler) |
| Zapier Table | Table A (Forex) / Table B (Futures) —Market_Loss_When_Stopped, Severance_Pay, Retry_Discount per levelTable C (Discount_Code_Duration_Days)Table F (Defense Configuration Matrix, Level 9+ — Defense Gate lookup only, full ownership at UC_4.15.4)Table J (Full Challenge Price, locked_rebuy_price) |
| 3rd Party | Rithmic Live FCM Gateway (Ironbeam)MT5 Manager API 'Disable/Read-Only' + C++ MT5 Plugin (flatten) TraderEvolution Admin API Discord Bot (Node.js, POST /discord/revoke-all-roles)QuickBooks Online (GL Posting)Typeform (native-hosted exit survey)Klaviyo (retention email via Flow 7B Path B)Internal Slack (Critical Alert — Balance < 0) |
2. Trigger
Middleware detects: Net_P&L <= −Market_Loss_When_Stopped
Formula:
Market_Loss_When_Stopped is looked up directly from Table A (Forex) or Table B (Futures) by the trader's Current_Level
Worked example (LIVE Level 1, Forex, $25,000 notional tier): Market_Loss_When_Stopped = $1,250 (Table A) → Hard Breach fires when Net_P&L <= −$1,250.
Net_P&L = Realized P&L + Unrealized P&L- Detection runs continuously via the execution-gateway
ACCOUNT_METRICSstream (Rithmic/MT5/TraderEvolution) — identical monitoring architecture to SIM - Once triggered, the decision is final — no recalculation or rollback even if post-flatten slippage changes P&L
3. Pre-conditions
- Trader has an active LIVE account (
Status = Active_DMA) - Middleware maintains a persistent connection to the execution gateway
Net_P&Lis tracked in real-time viaACCOUNT_METRICSstream
4. Post-conditions
Immediate (T+0):
- All open positions flattened via execution gateway
- All working orders cancelled
- Frontend renders Failure Modal with "Frosted Glass" full-dashboard blur
- DB updated with current Equity, Balance, Closed_Trades
- DB
Statusupdated to'Terminated',failure_timestamp = NOW() - Trading sub-account is locked (Read-Only) — NOT immediately deleted.
- Dashboard screen: permanently frosted (blurred, non-interactive). Data rendered underneath the frost is the static snapshot captured at the exact moment of the hard breach (equity, balance, closed trades, charts as they stood at
failure_timestamp) — NOT live data, NOT reset to a blank state -
- Notification bell is NOT frozen: notifications continue to arrive, unaffected by the Hard Breach/Frosted Glass state.
- All other screens (Account, Settings, etc.): render normally, no blur, no restrictions.
- Trader can purchase Re-Buy at discounted price during this window — see UC_4.15.3.
After archive_date (Failsafe fires):
- Historical ledger data purged from the active dashboard view → archived to
user_account_history(SQL database retains the full performance ledger; only the active UI view is purged). - Broker-specific Failsafe actions: see BR_4.15.2.7.
- At this point the dashboard resets to a blank D=0 state.
- Re-Buy pricing after window expiry depends on
is_founder: IFis_founder == TRUE→locked_rebuy_price; IFis_founder == FALSE→ Full Challenge Price (Table J).
Re-Buy Exception: if the trader purchases Re-Buy before the window expires, the backend's atomic reset immediately wipes the failed state and resets the dashboard to D=0 for the new challenge.
Dashboard access:
- Dashboard login never expires. Trader can return at any time.
5. Basic Flow
Detect breach: middleware continuously monitors Net_P&L from the execution-gateway stream (ACCOUNT_METRICS) and checks Net_P&L <= −Market_Loss_When_Stopped as fills arrive and P&L updates → Breach confirmed, then trigger Flow 7 as below:
Flow 7 (Financial Reporting / Recycling Logic) — full pipeline
Step 1 — Defense Gate:
-
IF Resignation == True→ SKIP Defense Gate, proceed directly to Liquidation (Step 4 Atomic Kill Switch). This path is entered via Flow 20 — see §8 Business Rules / Stagnation & Alternate Entry Points for the full description. -
Eligibility check:
IF Current_Level >= 9 AND Defense_Used == False→ eligible for Defense. Otherwise → ineligible, proceed to termination.- If eligible → trigger Flow 4B webhook (Defense Handoff), HALT Flow 7 — check details for defense case in UC_4.15.4 (Scenario C: Defense Protocol).
- If ineligible (
Current_Level < 9ORDefense_Used == True) OR resigned → continue through Flow 7 (termination path).
-
Atomic Kill Switch:
- Lock: Disable order entry via Broker API
- Flatten: Send Market Close for ALL open positions
- Cancel: Cancel all working orders (pending orders)
- DB Update:
Status = 'Terminated',failure_timestamp = NOW() - Lock sub-account (Read-Only): the middleware locks the trading sub-account (Read-Only) at T+0.
- Fire event: Middleware pushes
LEVEL_STOP_BREACHto the frontend AND to Zapier — payload (Note: Sotatek can modify if needed):
Field Type Description event_typestring "LEVEL_STOP_BREACH"user_idstring Trader's user ID net_pnlfloat Current Net P&L at breach (negative float) market_loss_when_stoppedfloat Account's per-level stop threshold (negative float, from Table A/B) amount_over_stop_lossfloat Amount by which Net P&L exceeded the stop loss [CHR-69]Amount_over_stop_loss = |Net_PnL at hard breach| − Market_Loss_When_Stopped|Net_PnL at hard breach|: absolute Net P&L (Realized + Unrealized) at the momentLEVEL_STOP_BREACHfires.Market_Loss_When_Stopped: per-level Hard Stop Loss threshold (Table A/B).Amount_over_stop_loss: excess loss beyond the stop threshold (gap/slippage). Used in Flow 9 Severance deduction — see BR_4.15.2.5.
POST /fail-challenge(called with{ user_id, Reason: "Drawdown" }) only returns HTTP 200 when the account is CONFIRMED FLAT (Open_Positions == 0). The decision is final once triggered (BR_4.15.2.4). -
Frontend renders Failure Modal (immediate UI reaction to the WebSocket event, running in parallel with the rest of Flow 7 below):
-
"Frosted Glass" blur applied to the Dashboard screen only — same display rule as SIM, see BR_4.10.2.2. Other screens render normally.
-
There are 5 Failure Modal variants, chosen by
Current_Level,Defense_Used, andSeverance_Pay. See BR_4.15.2.6 for the full breakdown and wireframe references:# Level band Has Defense? Severance? Modal shown 1 1-8 No No Standard failure modal (no severance notice) 2 1-8 No Yes "Risk Parameter Breached" + Severance payout notice 3 9-24, Defense_Used == FALSEYes — "Drawdown Defense Activated" notice (Defense runs — checkUC_4.15.4) 4 9-24, Defense_Used == TRUENo (already used) No Standard failure modal — no severance, defense exhausted 5 9-24, Defense_Used == TRUENo (already used) Yes Failure-with-Severance notice — defense exhausted Wireframe assets for the base Hard Breach modal are listed at §9 Wireframe / UI.
-
Step 2 — Refund Check (Market Data):
IF Next_Month_Data_Paid == True (pre-paid market-data subscription within the last 3 days) → call POST /issue-refund with { user_id, type: "MARKET_DATA" }. Middleware looks up the original Gateway_Source and issues the refund via the matching API.
Note — Non-refundable gateway exception: If
Gateway_Sourceis Dusupay, Crypto (tbd), or any other APM that rejects automated reversal, the middleware must instantly catch the failure (or bypass the API attempt entirely for known-incompatible gateways) without blocking the rest of Flow 7. The system must instead:
- Log the transaction exception to the financial ledger database.
- Auto-generate a high-priority Freshdesk ticket for the Operations team. The ticket payload must contain:
user_id— the trader's User IDtransaction_id— the original Transaction IDgateway_source— the Gateway Sourcerefund_amount— the exact refund amountSame pattern as the irreversible refund branch in UC_2.8.2 §2.
Step 3 — Ledger Close:
Call POST /financial/reset-ledger with { deactivate: true } to set ledgers.virtual_equity = 0. virtual_equity is the primary internal balance tracker on the Ledgers table — initialized at Live Onboarding (Flow 3H), updated with new capital on promotion (Flow 4), and reset to 0 here on failure.
Step 4 — Liquidation: Flatten positions (second pass — a confirming safety re-check on top of the real-time Kill Switch already executed in Step 1's Otherwise branch above, in case any position opened in the gap between breach detection and Flow 7 pickup).
Step 5 — Balance Check (Flash Crash Protection):
IF Balance < 0 → trigger a Critical Alert routed to the #ops-general Slack channel (ID: C0BR8LRC5MK — Production) / #test-ops-general (ID: C0BR6UXRR8D — Test) AND log to the Bad_Debt_Log SQL table for tax write-off. Bad_Debt_Log should contain user_id, fcm_subaccount_id, date, and negative_balance_amount. (Ref: CR-15.2)
Step 6 — Retention Gate → Severance Protocol:
IF Severance_Pay > 0(looked up from Table A/B byCurrent_Level) → Execute Flow 9.IF Severance_Pay == 0(or NULL) → Skip Flow 9.- Full Flow 9 payout logic (Authorized_Amount deduction math, Path A/B/C routing by contractor status) — see BR_4.15.2.5.
Step 7 — Post-Termination Access Control:
Call POST /system/set-account-state with { user_id, state: "Terminated" }.
-
Trading sub-account is NOT hard-deleted at this step. The sub-account remains in a locked (Read-Only) state from T+0. Trading is permanently blocked, but the account record and performance ledger are fully intact in the SQL database.
-
Dashboard login remains active — the trader can still log in at any time to view their frozen dashboard and to access the Re-Buy CTA. No login expiry is applied.
-
Sub-account deletion is deferred — hard-delete only occurs under one of two conditions:
archive_dateFailsafe fires (cron job) — broker-specific cleanup runs (see BR_4.15.2.7).- Trader purchases Re-Buy before
archive_date→ atomic reset cleans up the locked sub-account as part of Re-Buy provisioning (see UC_4.15.3 and BR_4.15.2.7 Case A).
Step 8 — Community (Digital Eviction):
Call POST /discord/revoke-all-roles with { user_id }. The Node.js Discord Bot removes "Pod Member", "Pod Leader", and all Title Roles using the trader's stored discord_user_id. (Not run for the Founding Mentor path — see §6 Alternative Flow, which explicitly keeps Pod Leadership/Discord roles intact.)
Step 9 — GL Posting:
Log P&L to QuickBooks Online. Payload should include user_id, termination date, and final realized P&L to close out the ledger.
Step 10 — Feedback Survey Gate:
Query the Users table for pod_leader_id. IF pod_leader_id IS NOT NULL (trader was in a pod) → embed a Typeform exit-evaluation survey link directly inside the Live_Account_Closed email (Step 11) and update last_survey_date = Today.
The form is natively hosted by Typeform (no build required); Typeform handles the webhook payload on submission.
Step 11 — Notification:
Send the Live_Account_Closed email with the Typeform link. Suppression gate: IF this Flow 7 run was triggered by Flow 19 (Stagnation Monitor, Reason Code == STAGNATION) → SKIP this email (silent skip — Flow 19 already sent its own Stagnation_Termination email; sending both would collide). See suppression logic in UC_4.15.4 BR_4.15.4.4.
Flow 7B (Retention & Retargeting) — separate flow, Path B only
Flow 7B is a separate database-webhook listener — it is NOT a sequential step of Flow 7. It fires on two distinct triggers, both of which write Status = 'Terminated' into the database:
- Trigger A — Hard Breach: Account
Statuschanges to'Terminated'via Step 1's Atomic Kill Switch (real-time breach detection or Stagnation Monitor). - Trigger B — Voluntary Resignation: Trader clicks the "Resign Account" button →
RESIGNATION_EXECUTEDwebhook fires → Flow 7 runs withReason = VOLUNTARY_RESIGNATION→Status = 'Terminated'is written. Flow 7B fires on the same state change.
In both cases Flow 7B runs independently alongside the rest of Flow 7's pipeline:
- Trigger: Account
Statuschanges toTerminated. - Action 1 — Cool-Down: Delay 1 Hour (gives the trader time to click the Dashboard Re-Buy CTA before the marketing email fires).
- Action 2 — Purchase Check:
IF Last_Purchase_Date > Failure_Timestamp(trader already re-bought during the cool-down window) → STOP, no email sent. - Action 3 — Path Router: checks
is_professional == TRUE:
- IF
is_founder == TRUE→locked_rebuy_price - IF
is_founder == FALSEAND withinfailure_timestamp + Discount_Code_Duration_Days→Challenge_Price × (1 − Retry_Discount)(Table A/BRetry_Discount, base price from Table J byCurrent_Levelat time of failure) - IF
is_founder == FALSEAND expired → Full Challenge Price (Table J)
- Action: Emit
Retention_Offer_Discountpayload to the Klaviyo API withuser_name,current_level, and the targetedDiscounted_Pricevalue. - Action 4 — Follow-Up Marketing (out of system scope): Klaviyo monitors the conversion lifecycle natively. IF no new transaction within
failure_timestamp + Discount_Code_Duration_Days(Table C) → Klaviyo executes theCoupon_Expiring_Soonfollow-up broadcast.
6. Alternative Flow
-
[Founding Mentor Hard Breach]
-
If
Role_Flag = 'Founding Mentor'and the overlay has NOT yet been acknowledged for this breach event, the Failure Modal is replaced by the Founding Mentor-specific overlay — identical re-summon rule to SIM, see UC_4.10.2 §6 — Wireframe: Hard breach for founding mentor.png (shared wireframe with SIM, no separate LIVE asset). -
After acknowledgement: routes straight into pricing + modal, same as SIM. The only difference is the modal itself:
- System calls
POST /calculate-cart(Quaderno tax calculation) → price is locked atlocked_rebuy_price(Founders always uselocked_rebuy_price, neverlocked_reset_price, which is SIM-only). - Re-Buy Modal opens directly
- System calls
-
Capital Protection (runs immediately, no bypass): identical to SIM — all positions flattened, all working orders cancelled.
-
Administrative Termination: identical to SIM — Discord roles are NOT revoked, Pod assignments remain intact.
-
7. Exceptional Flow
Identical to SIM — see UC_4.10.2 §7 Exceptional Flow.
8. Business Rules
BR_4.15.2.2: Frosted Glass — Permanent Until Re-Buy
Identical to SIM — see BR_4.10.2.2, substituting "Re-Buy" for SIM's "Reset".
BR_4.15.2.3: Discount_Code_Duration_Days — Dynamic Configuration
Identical to SIM — see BR_4.10.2.3.
BR_4.15.2.4: Immediate Triggering — No Rollback
Identical to SIM — see BR_4.10.2.6.
BR_4.15.2.5: Severance Protocol (Flow 9) — Eligibility and Payout
-
Eligibility:
Severance_Pay > 0for the trader'sCurrent_Level(Table A/B lookup) → If not, HALT. -
Deduction math:
Authorized_Amount = Severance_Pay − (Amount_Over_Stop_Loss if > $100)— slippage under $100 is forgiven; slippage over $100 is deducted in full.[CHR-69]Amount_over_stop_loss = |Net_PnL at hard breach| − Market_Loss_When_Stopped- Eg:
- Severance pay = 225 and Amount_Over_Stop_Loss = 125 → Authorized_amount = 225 - 125 = 100
- Severance pay = 225 and Amount_Over_Stop_Loss = 25 → Authorized_amount = 225
- Eg:
-
Reason override:
- IF
Reason == TERMINATION_FOR_CAUSE(fraud, malicious activity, chargeback dispute — manually flagged by Operations, not automatically detected) → Severance = $0. - IF
Reason == LAYOFF/NO_CAUSEorVOLUNTARY_RESIGNATION→ pay fullSeverance_Pay(no Stop-Loss deduction). Note: Reason = VOLUNTARY_RESIGNATION: trigger when user clicks the "resign account" button. - Ordinary breach: Hit hard breach,
Reason == DRAWDOWN→ Calculate Authorized_amount normally.
- IF
-
Authorization: Payout is initiated when a Marketing User clicks the "Authorize" button inside the Zapier Interface (linked via an ActiveCampaign Task). The Node.js middleware simply exposes the
Process Severance Payoutendpoint — Zapier holds state and waits for the human to authorize. The human interaction occurs completely outside of the Node.js middleware. On-click, Zapier:- Creates an ActiveCampaign task with the authorized amount and script template.
- Script template: This is simply a text prompt for the marketing team to use during the phone call. Do not need to code the content. Just ensure the payload field exists so marketing can map their copy in Zapier.
- Queries
billing_countryandcurrent_levelto determine the payout path. - Sends
payout_amountvia the corresponding API.
Path routing by contractor status at time of failure:
Path Condition API Path A — US Contractor (Levels 1-5) billing_country = 'US'ANDcurrent_level1-5Dots API Path B — International (All Levels) billing_country != 'US'(all levels)Dots API Path C — US W-2 (Level 6+) billing_country = 'US'ANDcurrent_level >= 6Rippling Off-Cycle Payroll API Note: Severance is paid regardless of whether the trader chooses to execute a Re-Buy.
- Creates an ActiveCampaign task with the authorized amount and script template.
-
Every payout is logged and must be visible on the trader's Billing screen.
BR_4.15.2.6: Failure Modal Variant by Level Band
Wireframe source: References/Wireframe/Stage 2.2/Failure and recovery/
Severance availability is independent of level band — a trader at any level within 1-8 may or may not have severance depending on the Table A/B lookup. The level band determines which wireframe variant and modal copy to use.
| # | Level band | Defense_Used | Severance notice | Wireframe | Modal description |
|---|---|---|---|---|---|
| 1 | 1-8 | — | No | Level 1 - 8_ Failure modal, no severance, no defense.png | Standard failure modal (no severance notice) |
| 2 | 1-8 | — | Yes | Level 1 - 8_Failure modal with Severance notice. No defense.png | "Risk Parameter Breached" modal with Severance payout notice |
| 3 | 9-24 | FALSE | — (Defense runs) | Level 9 - 24_ Drawdown defense notice.png | "Drawdown Defense Activated" notice — Defense runs (seeUC_4.15.4) |
| 4 | 9-24 | TRUE | No | Level 9 - 24 Failure modal with no severance, no defense.png | Standard failure modal — defense already used,Severance_Pay == 0 |
| 5 | 9-24 | TRUE | Yes | Level 9 - 24_ Failure modal with Severance notice. Defense exhausted.png | Failure-with-Severance notice — defense already used,Severance_Pay > 0 |
Level 9-24 has three termination modals (Variants 3, 4, 5):
- Variant 3 (
Defense_Used == FALSE): "Drawdown Defense Activated" — account enters Defense Protocol (UC_4.15.4); Flow 7 termination pipeline is halted. This modal is shown, but the account is NOT terminated. - Variant 4 (
Defense_Used == TRUE,Severance_Pay == 0): Failure modal, no severance — account is terminated through Flow 7 normally. Header: "Risk Parameter Breached" / sub-title: "Trading Revoked"; body text specific to Level 9-24 drawdown breach. No severance notice box. Screen description: UC_4.15.3 §10.3. - Variant 5 (
Defense_Used == TRUE,Severance_Pay > 0): Failure-with-Severance — account is terminated through Flow 7 normally, severance payout notice displayed.
BR_4.15.2.7: Broker-Specific Failsafe and Re-Buy Provisioning (LIVE) [CHR-61] [CHR-62]
archive_date — Broker-Specific Calculation:
| Marker | Name | Definition |
|---|---|---|
| M1 | Financial EOM Failsafe | 23:00 UTC on the last calendar day of the current month (end-of-month cutoff) |
| M2 | Discount Window Expiry | failure_timestamp + Discount_Code_Duration_Days (Table C, default 10 days) |
Broker routing:
| Broker | archive_date formula | Rationale |
|---|---|---|
| Rithmic | Min(M1, M2) | Whichever fires first triggers the Failsafe — EOM financial close takes precedence if it arrives before M2. |
| MT5 | M2 only | No EOM financial close dependency; plain discount-window expiry. |
| TraderEvolution | M2 only | Same as MT5. |
Example (Rithmic): Trader fails on 25 Aug. M2 = 4 Sep (25 Aug + 10 days). M1 = 31 Aug 23:00 UTC. →
archive_date = 31 Aug 23:00 UTC(M1 fires first).
Rithmic — Server Architecture & ID Rules
Rithmic runs two distinct server environments:
- Paper Trading Server — SIM accounts
- Live Trading Server — Live accounts (Ironbeam controlled)
These are separate gateways. A Re-Buy (Live → SIM rollback) must provision the new sub-account on the Paper Trading Gateway — the Live sub-account and Live server are never reused.
ID Mapping: Rithmic assigns two independent gateway-level User IDs per trader:
| ID | Server | Mapped to |
|---|---|---|
| Rithmic Live User ID | Live Trading Server (Ironbeam) | PostgreSQLuser_id (UUID) |
| Rithmic SIM User ID | Paper Trading Server (SIM) | PostgreSQLuser_id (UUID) |
Both IDs must be explicitly mapped to the master PostgreSQL user_id (UUID) at all times. The two IDs are fully independent — enabling or disabling one has no effect on the other.
Live Onboarding state change: When a trader's SIM account is promoted to Live, the system disables the Rithmic SIM User ID and unassigns the SIM sub-account. Any rollback to SIM (Re-Buy) must therefore explicitly re-enable the Rithmic SIM User ID before the new SIM sub-account can be provisioned.
Pre-Archive Gate — Data Integrity Sync
Before executing any broker-side cleanup (unassign / delete), the system must verify that all final trade data and P&L snapshots for the failed LIVE account are successfully written to:
user_account_history(PostgreSQL)- AWS S3 Glacier — immutable system of record for all trade logs and compliance data, operating independently of the execution platforms
No cleanup action may proceed until both writes are confirmed. This gate applies at two trigger points:
- Failsafe (
archive_datefires): archive runs before Rithmic unassign or MT5/TE hard-delete. - Case A (Re-Buy before Failsafe): archive runs before any broker-side cleanup as part of Re-Buy provisioning.
Failsafe — actions when archive_date fires (after Pre-Archive Gate passes)
| Broker | Failsafe Action |
|---|---|
| Rithmic | (1) Disable Rithmic Live User ID on the Live Trading Server. (2) Revoke Live Pro Market Data — revoke all active feed entitlements on the LIVE sub-account. (3) Unassign LIVE sub-account. |
| MT5 | Hard-delete LIVE sub-account. |
| TraderEvolution | Hard-delete LIVE sub-account. |
Case A — Re-Buy purchased BEFORE Failsafe (within archive_date)
Locked LIVE sub-account still exists. Pre-Archive Gate runs first, then Re-Buy provisioning executes the full Live-to-SIM rollback.
| Broker | Re-Buy Provisioning |
|---|---|
| Rithmic | (1) Disable Rithmic Live User ID on the Live Trading Server. (2) Revoke Live Pro Market Data — revoke all live feed entitlements. (3) Unassign LIVE sub-account. (4) Re-enable Rithmic SIM User ID (was disabled when the trader went Live). (5) Provision brand-new SIM sub-account on the Paper Trading Gateway and assign to Rithmic SIM User ID. (6) Handle Market Data (Futures only) — present Market Data re-select screen: reuse existing SIM entitlements or re-purchase per BR_4.15.2.8. |
| MT5 | Hard-delete locked LIVE sub-account. Provision brand-new SIM sub-account. |
| TraderEvolution | Hard-delete locked LIVE sub-account. Provision brand-new SIM sub-account. |
Case B — Re-Buy purchased AFTER Failsafe (after archive_date)
Failsafe has already run: Rithmic Live User ID disabled, Market Data revoked, LIVE sub-account unassigned (MT5/TE: hard-deleted). Archive already completed at Failsafe time. Re-Buy only needs to restore SIM access and provision the new account.
| Broker | Re-Buy Provisioning |
|---|---|
| Rithmic | (1) Re-enable Rithmic SIM User ID (was disabled when the trader went Live). (2) Provision brand-new SIM sub-account on the Paper Trading Gateway and assign to Rithmic SIM User ID. (3) Handle Market Data (Futures only) — Market Data already revoked by Failsafe; present Market Data re-select screen: reuse existing SIM entitlements or re-purchase per BR_4.15.2.8. |
| MT5 | Provision brand-new SIM sub-account (LIVE account already deleted by Failsafe). |
| TraderEvolution | Provision brand-new SIM sub-account (LIVE account already deleted by Failsafe). |
BR_4.15.2.8: Market Data Re-Select Screen (Rithmic Futures Re-Buy only) [CHR-62]
- Applicable only to Rithmic Futures traders purchasing Re-Buy.
- After Re-Buy payment succeeds, the frontend presents a Market Data re-select screen that persists (non-dismissible) until the trader clicks "Complete". The screen re-displays on every page reload or re-login until selection is submitted — the trader cannot access the dashboard before completing this step.
- This screen is required because the old Live Pro data entitlements were revoked at failure time (Case A) or by Failsafe (Case B), and the new SIM sub-account starts with no active entitlements. The trader must select their SIM Non-Pro data package before they can access the dashboard.
- Forex brokers (MT5, TraderEvolution) do not present this screen — there is no per-user market data subscription for Forex.
| Scenario | Backend behaviour |
|---|---|
| Feed downgrade or exact match | Newly selected exchanges are equal to or a strict subset of currently active exchanges. Backendreuses existing active entitlements — no new purchase. |
| Feed upgrade | User selects additional exchanges not currently active. Backend provisions only the missing exchanges. If the new total is ≤ 3 exchanges, charge = new count × $18. If new total = 4 exchanges, charge = $54 (4th free). |
| Feed swap | User drops one active exchange and selects a different one. Backendretains the sunk cost of the dropped exchange (no refund) and purchases the new exchange a la carte at $18.00 (unless the 4-for-3 bundle applies, in which case the 4th is free). |
SIM feed reuse example:
A trader purchases a SIM challenge on 2 Aug and selects 3 exchanges (CME Level 2, CBOT, NYMEX). On 3 Aug they go Live, fail the Hard Breach on the same day, and immediately purchase a Re-Buy.
- At Re-Buy: their SIM entitlements are still active on the Paper Trading gateway for the current billing period.
- The Market Data re-select screen is shown. If the trader selects the same 3 exchanges (exact match) → backend detects active entitlements and reuses them without charging again.
- If the trader drops to 2 exchanges (downgrade) → backend reuses the 2 active ones, no purchase.
- If the trader adds COMEX as a 4th exchange (upgrade) → backend provisions the 4th exchange at $18
Wireframe / UI: Hard Breach modals and the Market Data re-select screen are documented in UC_4.15.3 §9–§10.
Changelog
| Date | Version | Updated item | Before | After | Notes |
|---|---|---|---|---|---|
| 2026-08-18 | v1 | Initial creation | — | Full SRS with 7 BRs (BR_4.15.2.2–.8), Overview, Trigger, Pre-conditions, Post-conditions, Basic/Alternative/Exceptional Flow, Wireframe | Authored per Init Flow Step 3 (Architect), sourced from QnA_init_docs.md (6 BA-confirmed items) andUC_4.10.2 (SIM architecture base). |
| 2026-08-24 | v4 | BR_4.15.2.7 — Added broker-specificarchive_date calculation (M1/M2 logic) | archive_date referenced without definition | Rithmic:archive_date = Min(M1, M2) where M1 = 23:00 UTC last day of month (Financial EOM Failsafe), M2 = failure_timestamp + Discount_Code_Duration_Days; MT5/TE: archive_date = M2 only. Worked examples added. | — |
| 2026-09-03 | v6 | §6 Flow 7B Path B Action 3 pricing route + Action 4 out-of-scope note — window anchor made explicit | within Discount_Code_Duration_Days | within failure_timestamp + Discount_Code_Duration_Days | Editorial — matches the anchor wording already used in BR_4.15.2.7 M2 and UC_4.15.3 BR_4.15.3.1. No logic/value change. |
| 2026-08-25 | v5 | BR_4.15.2.8 — Removed cap enforcement note + BN-09 reference | Blockquote:"Cap enforcement: Maximum aggregate monthly spend per user_id = $54.00. If the selected feeds would exceed this cap, the backend rejects the request and the frontend displays BN-09." | Removed. This case cannot occur: the Non-Pro bundle maxes out at 4 exchanges (CME + 3 optional), priced at $18 × 3 + 1 free = $54 flat. No selection can exceed $54; the error path is unreachable. BN-09 also removed from list-toast-popup.md and UC_4.15.3. | BA decision 2026-08-25. |