StackTrading Docs

Common Business Rules

Project: Stack Trading Date Created: 2026-07-22 Version: v1.25 Last Updated: 2026-11-09

This document defines common business rules that repeat across multiple screens or UCs. Rules that appear only in a single flow/UC belong in that UC's SRS doc, not here.


CR-01: Numeric Fields

Applies to all numeric input fields (integer only). Does NOT apply to phone numbers, zip/postal codes, or identification numbers — those follow their own format rules specified in the UC.

1.1 Character Validation — Real-Time Block

CriterionRuleError Message
Valid charsAllowed: digits0–9. On invalid keystroke → Block — character does not appear in the field, no message shown—
Paste — invalid formatReject entire string — nothing is inserted. Show red inline error below field immediately"Invalid number format"

1.2 Length Limit

CriterionRuleError Message
Max lengthMax15 digits. Typing the 16th digit → Block, no message—
Paste exceeding limitReject entire string, no auto-truncate. Show red inline error immediately"[Field name] must not exceed [max] characters"

1.3 Auto-format (no error shown)

CriterionRule
Leading zeroAuto-remove when user types a second digit. E.g.09 → 9
Leading/trailing spacesKeep while typing; auto-trim on out-click

1.4 Placeholder & Required

CriterionRuleError Message
PlaceholderDisplay*"Enter [field's label]"* when field is empty—
Required field — emptyOn out-click → show red inline error below field + red border. Error auto-clears when user types a valid character"Please enter [field's label]"

CR-02: Text / Textarea / Search Fields

Applies to all Textbox, Textarea, and Search inputs.

2.1 Whitespace Auto-Trim

CriterionRule
Leading/trailing spacesKeep while typing (no UX disruption). Auto-trim on out-click
Spaces-only inputTreated as empty — applies required-field rule if applicable

2.2 Default Length Limits

Field TypeLimitOn Limit Reached
Textbox255 charsDo NOT block while typing. On out-click → red inline error below field + red border
Textarea500 charsDo NOT block while typing. On out-click → red inline error below field + red border
Search box255 charsBlock — character 256 cannot be entered, no message shown
Promo code input100 charsBlock — character 101 cannot be entered, no message shown

2.3 Placeholder

Field TypePlaceholder
Textbox / Textarea"Enter [field's label]" — specify exact label, e.g. "Enter email"
Search box"Search"

2.4 Required Field & Errors

Required timing is IDENTICAL for all field types: "On out-click"

CriterionRuleError Message
Required — emptyOn out-click → red inline error below field + red border. Error auto-clears when user types valid input"Please enter [field's label]"
Over max — Textbox/TextareaOn out-click → red inline error below field + red border. Error auto-clears when input is trimmed to valid length"[Field name] must not exceed [max] characters"
Under minOn out-click → red inline error below field + red border. Error auto-clears when input meets minimum length"[Field name] must be at least [min] characters"

2.5 Search Behavior

CriterionRule
Real-time searchFilter and display results as user types each character — no Enter required
Case sensitivityCase-insensitive

CR-03: Dropdown

Applies to all Dropdown / Combobox components.

CriterionRuleError Message
Default stateShow*"Select [field's label]"* placeholder. No option pre-selected unless UC specifies a default—
Searchable[CHR-99]Every dropdown renders a search/filter input inside the open option list — user can type to narrow the visible options by substring match (case-insensitive). Applies regardless of option count.—
Long option textTruncate with... in the field. Hover → tooltip shows full text—
After selectionClose dropdown; display selected value in field. No✕ clear icon—
Re-open dropdownCurrently selected option is highlighted (checked/bold) in the list—
Required — emptyOn out-click → red inline error below field + red border. Error auto-clears when user selects a valid option"Please select [field's label]"

CR-04: Filter Dropdown — Default "All"

Applies to filter controls on list screens. Does NOT apply to form dropdowns.

CriterionRule
"All" optionEvery filter dropdown MUST have an"All" option at the top of the list
Default valueOn first load →"All" is selected; all records are displayed
ResultsUpdate immediately on filter change — no confirmation needed
DistinctionForm dropdown: placeholder"Select [field's label]", no "All" option — see CR-03

CR-05: Unsaved Data Navigation Warning

Applies to screens with data-entry forms.

5.1 Trigger Conditions

ConditionDescription
Form is dirtyUser has changed at least one field since the form loaded
Navigation awayUser clicks [Cancel], switches tab, uses breadcrumb, or any method to leave the current screen
No triggerForm has not changed → navigate normally, no popup

5.2 Warning Popup Content

Ref: CF-01


CR-06: List Pagination

CriterionRule
Default page size10 records per page
Page size options10, 20, 50, 100. Change → reload list, return to page 1
[Previous] buttonDisabled on page 1
[Next] buttonDisabled on the last page
Info display"Showing [start]–[end] of [total] records"

CR-07: File Upload

Applies to screens with upload features. Screen applicability defined in the UC. File count, size limit, and format MUST be taken from UC. Do NOT hardcode defaults.

7.1 Upload Limits

CriterionValueSource
Maximum file count[From UC]UC must specify
Allowed formats[From UC]UC must list exact extensions
Max size per file[From UC]UC must specify (e.g., 5 MB, 10 MB)

7.2 Error Messages

ViolationError Message
Wrong format"File [filename] is not an accepted format. Accepted formats: [list from UC]"
Exceeds file count limit"Maximum [N] files allowed"
File exceeds size limit"Please select a file smaller than [N] MB"
Server error during uploadError toast : "Failed to upload file. Please try again later"

7.3 Upload Area States

Screen ModeState
Create / EditEnabled — user can add or remove files
View DetailDisabled (read-only) — show file list only

CR-08: Timestamp Standard — UTC / ISO 8601 / Millisecond Precision

Applies to all date/time values across the entire stack: API request and response payloads, database columns, log entries, and webhook parameters.

8.1 Required Standard

AttributeSpecification
TimezoneUTC only. Local timezones must never be stored or returned.
FormatISO 8601 —YYYY-MM-DDTHH:mm:ss.sssZ
PrecisionMilliseconds (.sss) — required so logs can measure sub-50ms operations
DB column typeTIMESTAMP WITH TIME ZONE storing UTC
ScopeAPI request payloads, API responses, database columns, log entries, Zapier webhook parameters

8.2 Exception

Issuing platforms and brokers (e.g. CME exchange session rollover) manage localized market session schedules independently. Stack Trading's timestamp standard applies only to Stack Trading's own stack and does not override exchange-side time configurations.

8.3 Affected Fields (Non-Exhaustive)

Fields confirmed in source documents that must conform to this rule:

Field / ColumnLocation
timestamp_utcAPI:POST /execute-checkout input payload
expiration_dateEvaluation lifecycle (DB + API response)
created_at, updated_atAll DB tables (audit metadata)
start_date timestamp_utcEvaluation start tracking
Session_Open_UTC, Official_Close_UTCMarket session DB columns (Zapier tables)
Halt_Start_UTC, Halt_End_UTCMarket session halt window columns
Last_Ingested_UTCData ingestion audit checkpoint
next_state_timestamp/system/market-status response — "ISO8601" format

CR-09: Special Field Types

Applies to Email and Phone Number input fields across the system. Rules here override CR-02 defaults where specified.

Note: No phone number field has been identified in customer supplies to date. This rule is defined preemptively for future UCs. If a UC introduces a phone field, reference §9.2 and specify any UC-specific constraints inline.


9.1 Email Field

CriterionRule
Placeholder"Enter email"
Max length100 characters (overrides CR-02 default of 255)
Required charactersMust contain@ and at least one . in the domain part
Allowed charactersLetters (a–z, A–Z), digits (0–9),. (dot), _ (underscore), - (hyphen)
Prohibited charactersSpaces, accented characters, and special characters (e.g.!, #, $, ,) — blocked on paste; flagged on out-click
Format[local-part]@[domain].[tld] — e.g. user@gmail.com
Auto-trimLeading and trailing spaces automatically removed on out-click
Validation timingOn out-click (not real-time)

Validation errors:

SituationTimingError Message
Required field — emptyOut-click"Please enter email"
Invalid formatOut-click"Please enter a valid email address"
Exceeds 100 charactersOut-click"Email must not exceed 100 characters"

9.2 Phone Number Field

CriterionRule
Placeholder"Enter phone number"
Input structureTwo-part field:[Country Code selector] (prefix, left) and [Number input] (right)
Country Code default+1 (United States) on first load
Country Code selectorScroll-only — no search input; user browses the country list by scrolling
Country Code — valid charactersDigits (0–9) only, no+, no spaces, no special characters. Regex: ^[0-9]{1,3}$.
Phone Number — valid charactersDigits (0–9) only, no+, no spaces, no special characters. Letters and special characters are blocked in real-time. Regex: ^[0-9]{1,20}$. Required.
Auto-trimLeading zeros in the number input are automatically removed on out-click
LengthCountry Code: 1–3 digits. Phone Number: 1–20 digits.[CHR-106]
Submitted / stored formatThe Country Code and number are concatenated into a single string (e.g.14155552671) — no separator, no spaces. This combined value is what's sent in the API payload (phone_number) and stored in the DB. The UI keeps the two-part input for entry, but the value leaving the form must always carry the country code.
Validation timingOn out-click and on submit

Validation errors:

SituationTimingError Message
Required field — emptyOut-click / Submit"Please enter phone number"
Invalid length / format (phone number, fails^[0-9]{1,20}$)Out-click / Submit"Please enter a valid phone number"
Invalid country code (fails^[0-9]{1,3}$)Out-click / Submit"Please select a valid country code"

CR-10: Tooltip Interaction

EnvironmentTriggerDismiss
DesktopHover over tooltip iconAuto-dismiss on cursor leave
MobileTap tooltip iconTap anywhere outside the tooltip
  • Tooltip content is static text only — no interactive elements (links, buttons) inside.
  • Tooltip does NOT block the flow or require user acknowledgement.

CR-11: Numeric / Monetary Value Display

Applies to all numeric and monetary fields displayed across the app — price, fee, discount, tax, total, balance, equity, PnL, and any other financial or numeric value shown on a screen.

CriterionRule
FormatDisplay with max 2 decimal places. Example:499.00, 11.94, 510.94.
Discount displayDiscount line items are displayed as a negative dollar amount:−$XX.XX (en-dash + dollar sign + value to 2 decimal places). Example: −$25.00. The value is the absolute discount_amount float returned by the server — never a negative float.
HoverEvery value always shows a tooltip on hover with thefull value. Ref: CR-10 for tooltip interaction behavior
Thousands separatorUse comma, for thousands grouping (e.g. 1,250.00).

CR-12: UTM Attribution Capture — Global, Root Layout

Source: Adrian Stack (client, Slack, 2026-07-30). Supersedes any UC-local UTM capture rule that scopes parsing to a single page/step — see CR-20260730-002.

Applies site-wide — every public page of the Marketing website, the Checkout App, and the Partner Application page. This is a cross-cutting rule, not specific to any single UC; individual UCs reference this rule instead of re-defining UTM capture logic.

12.1 Rationale

Users enter the site from unpredictable URLs (an ad may link to a blog post, an affiliate may link to the homepage, organic search may land anywhere). Because users navigate across multiple pages before converting, the system cannot rely on UTM parameters remaining in the active URL bar at the moment of conversion. Two attribution-critical paid-ad flows depend on this rule:

  • Associate Track landing page(s) → Checkout.
  • Partner landing page → Partner Application webform.

12.2 Global Root Execution

CriterionRule
WhereThe UTM parsing script sits in theroot layout component — fires on every single page load and every route change, across the entire frontend (Marketing website + Checkout App). Not isolated to specific pages.
WhenOn page initialization (mount) and on every client-side route change.

12.3 Persistent Storage — localStorage

CriterionRule
Storage mechanismlocalStorage (not sessionStorage, not in-memory state only) — so attribution survives a closed browser and a returning user on a later visit.
UTM parameters present in URLWriteutm_source, utm_medium, utm_campaign, utm_term, utm_content to localStorage. If old UTM values already exist in storage, overwrite them — this is deliberate last-touch attribution, not first-seen-wins.
No UTM parameters in URLDonothing. Do NOT clear localStorage. Do NOT overwrite existing values with null. Leave existing localStorage UTM values intact.

12.4 Payload Injection

At the moment of submission for any of the three conversion points below, the frontend component reads the current UTM values from localStorage and injects them into the outbound API payload:

Conversion pointUC reference
Partner Application submitPartner Application form (CR-20260726-005)
Join WaitlistUC_2.1.3 — direct ActiveCampaign + Klaviyo calls
Step 5 of CheckoutUC_2.6.1 / UC_2.6.2 POST /capture-lead, and POST /execute-checkout at Step 6

This guarantees acquisition source data is preserved and transmitted to Stack Trading's database, Klaviyo, and ActiveCampaign, even if the user clicks around the site, leaves, and returns later via a clean URL (no UTM params).


CR-13: Rounding to 2 Decimal Places

Applies to all backend-calculated numeric/monetary values that feed into threshold comparisons or are displayed — e.g. Daily_Loss_Limit, Net_P&L, and similar computed values.

CriterionRule
AlgorithmRound to nearest hundredth (2 decimal places), round-half-up. Use the code language's native rounding function (e.g.Math.round, toFixed) — no need to hand-code a carry-chain.
Examples624.99375 → 624.99. 624.99875 → 625.00.
RefDisplay formatting once rounded →CR-11.

CR-14: WebSocket Reconnection & Snapshot Resiliency (Shared)

Applies to every Dashboard widget/table fed by a WebSocket event (e.g. POSITION_METRICS, PERFORMANCE_UPDATE, and equivalent event channels across other Dashboard UCs).

CriterionRule
TriggerCloudflare edge routing can drop idle or long-running WebSocket connections; separately, the underlying market/exchange can go into an off-hours/closed state where no new events are emitted at all.
Backend snapshot persistenceThe Backend maintains and holds the latest data snapshot for each real-time widget/table (not merely re-broadcasting on push), so that on a fresh page load or a page reload (F5), the Frontend can restore the widget/table from that snapshot immediately — instead of rendering it empty while waiting for the next WebSocket event.
Reconnection behaviorFrontend implements exponential backoff and automatic reconnection to prevent UI freezing or silent data failures.
Data retention while reconnectingWidgets/tables retain their last-known snapshot values rather than clearing to empty while the WebSocket connection is temporarily unavailable or disconnected.
Market-closed behaviorIf the market is closed (no new events being emitted because there is no trading activity), the widget/table continues displaying the latest available snapshot data until new data becomes available — it does not reset to empty or zero merely because no real-time events are currently arriving.
Page reload (F5) behaviorOn page load/reload, the Frontend renders from the Backend's latest snapshot first, then applies subsequent WebSocket events on top of it. The widget/table is never shown empty purely because no new WebSocket event has arrived yet since load.
RefSource: RFQ_ Website and Dashboard Implementation V7.pdf (original reconnection-resiliency rule); Source: User instruction (BA session), 2026-08-31 (extends the rule to backend snapshot persistence, market-closed behavior, and page-reload/F5 behavior).

(Moved here from UC_4.2.1 §BR_4.2.1.4, which was scoped to a single widget but referenced by multiple sibling and external UCs — see Changelog. Extended 2026-08-31 to cover snapshot persistence, market-closed, and F5/reload behavior, per the same rationale — this is a shared cross-cutting concern, not specific to any one widget.)


CR-15: Reference

CR-15.1: Email

Support@stacktrading.com Marketing@stacktrading.com Compliance@stacktrading.com Sales@stacktrading.com no-reply@stacktrading.com


CR-15.2: Slack

Production Channels

#ops-treasury ID: C0BRCCMN1MG Receives Hourly Solvency Reports, Automated Treasury Sweep confirmations, and the Daily EOD Firm Health Report.

#ops-risk ID: C0BREC78LGH (Replacing #risk-ops): Receives High-Impact News Event summaries, Overnight Margin and Swap Monitor alerts, and TRIM_TO_COMPLIANCE gateway rejection Severity 1 alerts.

#ops-dev ID: C0BRCDB8U3U (Replacing #dev_ops): Receives the Configuration Database Backup success or failure notifications.

#ops-marketing ID: C0BQX3AV679 (Replacing #marketing): Receives fulfillment notifications, such as a Level 10 trader claiming a Tom James Suit or Goodwill Merch inventory depletion alerts.

#ops-onboarding ID: C0BRC4UE15F Receives E-Verify failures from Rippling's native Flow 6 onboarding.

#ops-general ID: C0BR8LRC5MK (The Catch-All): Designated for Veriff manual resets, FCM institution denial alerts, Dispute/Chargeback handlers, Pay raise logic confirmations, Pod Vesting completions, MID capacity warnings, and Aggregate Exhaustion Severity 1 alerts.

#ops-security ID: C0BQX3L74B1 (The Restricted Channel): A designated secure channel for receiving "High Volume Pod Reassignment" alerts to monitor internal administrators for abuse.

Development/Test Channels

#test-ops-onboarding ID: C0BQX1MDX47 Receives Background Check flags from E-Verify failures.

#test-ops-treasury ID: C0BRCBMGTC2 Receives Hourly Solvency Reports, Automated Treasury Sweep confirmations, and the Daily EOD Firm Health Report.

#test-ops-risk ID: C0BRAMTDYMQ Receives High-Impact News Event summaries, Overnight Margin and Swap Monitor alerts, and TRIM_TO_COMPLIANCE gateway rejection Severity 1 alerts.

#test-ops-general ID: C0BR6UXRR8D Designated for Veriff manual resets, FCM institution denial alerts, Dispute/Chargeback handlers, Pay raise logic confirmations, Pod Vesting completions, MID capacity warnings, and Aggregate Exhaustion Severity 1 alerts.


CR-16: Net PnL Display — Full Precision (Whole Dollars), No Abbreviation

Applies to any live Net PnL dollar-value display across the Dashboard (e.g. PnL Gauge center value, Daily Loss Limit Bar's dollar/remaining-amount label) — not to other monetary fields, which remain governed by CR-11.

CriterionRule
FormatDisplay the exact dollar amount using comma thousands separators, cents omitted (e.g.$1,875, not $1,875.00).
AbbreviationNever abbreviate (1.8K, 1M, etc.), regardless of magnitude.
Relationship to CR-11Deliberate exception toCR-11's 2-decimal-place default, for this field only — CR-11's thousands-separator and hover-tooltip (full value) rules still apply.
RefSource: Client description, relayed by user, BA session, 2026-08-31 (originally authored as UC_4.8.1 BR_4.8.1.6 point 1); Source: BA/user instruction, 2026-09-15 (extracted into this shared CR, and extended to the Daily Loss Limit Bar's dollar-value display, UC_4.7.5/UC_4.12.5 — no client source describes that widget's dollar label, added on explicit BA/user instruction).

(Moved here from UC_4.8.1 §BR_4.8.1.6 point 1 — originally a one-off exception to CR-11 scoped to a single widget, but already reused verbatim by UC_4.12.2 and now also applied to UC_4.7.5/UC_4.12.5. Follows the same generalization pattern as CR-14. See Changelog.)


CR-17: Soft Breach / Hard Breach — Widget Data Display Behavior (Shared)

Applies to every real-time Overview-screen widget covered by UC_4.2.1–4.2.5 (Position Monitor Table, The Pulse, Equity Curve, Profit Factor, Win Rate) and UC_4.8.1 (PnL Gauge). This CR governs data display behavior only — i.e. what the widget shows and whether it keeps updating. It does not govern breach trigger/lock/flatten mechanics (UC_4.10.1 Soft Breach, UC_4.10.2 Hard Breach) or Pulse Score's scoring-eligibility of flatten/cancel orders (Ref: UC_4.2.2 §6 Exceptional Flow), both of which are unchanged by this CR.

CriterionSoft Breach (Ref: UC_4.10.1)Hard Breach (Ref: UC_4.10.2)
While breach is activePositions/orders force-closed by the Soft Breach flatten still push their normal WebSocket event (POSITION_METRICS close, PERFORMANCE_UPDATE, etc.) the instant they are flattened/cancelled — the affected widget(s) update immediately, same as any trader-initiated close/cancel. Widgets are not frozen during the soft-lock window itself.Once the Atomic Kill Switch's flatten/cancel step completes andstatus is written to Failed, the backend stops emitting further real-time updates for that account — no more POSITION_METRICS/PERFORMANCE_UPDATE/equivalent events fire. Each widget's last-received values freeze in place (Ref: CR-14 retention-of-last-snapshot behavior, now permanent rather than temporary).
Data capture (snapshot-based widgets, e.g. Equity Curve)The underlying snapshot/history capture (e.g. the Equity Curve's 30-minute cron, Ref:UC_4.2.3 BR_4.2.3.4) pauses for the duration the account is under an active Soft Breach lock — no new snapshot is captured between the breach firing and reset_time auto-unlock. This supersedes the prior (2026-09-15) wording that snapshotting continued uninterrupted through Soft Breach.Data capture stops entirely once the account reachesstatus = Failed — same as the "while breach is active" row above; there is no further capture to resume, since the account does not return to active trading.
On Soft Breach auto-unlock (reset_time)Widgets keep showing the data accumulated before/during the lock window — nothing is cleared. Once the trader resumes trading after unlock, new activity displaysalongside (appended after) that pre-existing data, in the same session — consistent with Soft Breach carrying no archive and not being a failure (Ref: _QNA_INDEX.md, "Soft Breach KHÔNG phải failure và KHÔNG có archive"). Paused snapshot capture (row above) resumes on the next scheduled 30-minute tick after unlock.Not applicable here — Hard Breach has no auto-unlock; see "On Reset" row below.
On Reset (Hard Breach only)—Widgets donot reset to default automatically at the moment of breach or at archive_date firing on their own. The reset-to-Day-0/default display only occurs once a Reset/Re-Buy purchase completes successfully and a brand-new sub-account is provisioned and attached to the user (Ref: UC_4.10.2 §5.3 Reset Flow) — at that point every widget is simply reading a fresh account with no trading history yet, which is why it displays the same Day-0/empty-state values as a newly created account, not because any widget performed a "clear" operation on the old account's data. This matches the confirmed rule that the D=0/default dashboard state "KHÔNG BAO GIỜ reset khi failure, chỉ reset sau khi thanh toán Reset/Re-Buy thành công" (Ref: _QNA_INDEX.md).
RefSource: User instruction (BA session), 2026-09-19, relaying client requirement on Soft/Hard Breach data display; cross-checked againstUC_4.10.1, UC_4.10.2, and _QNA_INDEX.md (Soft Breach no-archive/not-a-failure; D=0 reset-only-after-successful-purchase).

(New shared rule, 2026-09-19 — consolidates the Soft/Hard Breach data-display behavior that otherwise would be repeated near-identically across all 6 widgets in scope. Per-widget sections in UC_4.2.1–4.2.5 and UC_4.8.1 cross-reference this CR and add only what is genuinely widget-specific, e.g. the Equity Curve's snapshot-cadence interaction (Ref: UC_4.2.3 BR_4.2.3.4) or the PnL Gauge's existing Breached dial state (Ref: UC_4.8.1 BR_4.8.1.5).)


CR-18: Inbound Webhook — No-Op Returns 200 OK and Drops the Payload (Shared)

Applies to every Middleware endpoint or webhook receiver called by Zapier, Typeform, Klaviyo or the Discord bot flows.

CriterionRule
When it appliesThe call arrives but its precondition is not met, or it would repeat an outcome that is already applied (e.g. the user already has the target state).
ResponseReturn200 OK. Do not return an error status.
PayloadDrop it — no data is written and no downstream action runs.
Calling flowThe calling Zap / flow is not failed or crashed, and no retry loop is triggered.
Extra side actionsAny additional action on the drop (e.g. a Slack alert to Operations) is defined in the owning UC, not here.

Known instances: UC_8.1.1 (Discord skip-if-unlinked) · UC_8.2.8 BR_8.2.8.7 (duplicate pod confirmation click) · Pod System Flow 10 / 10.1A (duplicate Style form submission, discord_user_id IS NULL, missing pod channel, Trading Plan submitted while on waitlist).


CR-19: Platform Provisioning & Third-Party Charting Platform Rules (Shared)

Applies to every UC touching trader platform provisioning (Checkout Step 3 — Select Platform, Zapier Flow 1 Step 3 POST /provision-sim-user), the license-validation endpoint, and Payout UCs that compute Sierra Chart reimbursement. This is a cross-cutting rule — individual UCs reference it instead of re-defining platform provisioning sequencing or the license API contract.

19.1 Provisioning Sequence — Rithmic-First (The Foundation)

CriterionRule
Step orderFor all of TradeSea, Quantower, ATAS, MotiveWave, and Sierra Chart, the middlewareMUST first provision the Rithmic trading account, because Rithmic is the actual execution and data engine. Once Rithmic credentials are created, the middleware evaluates platform_selection and executes the corresponding platform-specific flow (§19.2–§19.5).

19.2 [CHR-117] Sierra Chart — BYOL Disclaimer & Usage-Based Reimbursement

Affected UCs: UC_2.7-2.8, UC_4.15.2, UC_5.1, UC_7.3, UC_8.1.1.

1. Frontend Disclaimer. On the Checkout page, Step 3 (Selecting a platform): if Sierra Chart is selected, display this exact copy:

"Sierra Chart operates on a Bring-Your-Own-License (BYOL) model. You must purchase your own package. Stack Trading will reimburse your platform costs ($35/mo) directly to your payout account upon successfully passing your evaluation. Once funded, you will be reimbursed at the end of every Live Level. Note: To qualify for the reimbursement, our system must verify that Sierra Chart was used as your primary execution terminal for the majority of your active trading days."

2. Tracking. For every user, track platform_selection == 'Sierra Chart'.

ConditionResult
User status ever changes toFailed (hard breach on SIM env)Donot refund.

3. Reimbursement calculation. When a user moves from SIM to Live, and for every Live level progression, or when a user gets a hard breach on Live:

(1) Calculate payout ratio:

Payout_Ratio = Sierra_Chart_Days / Total_Active_Trading_Days
VariableDefinition
Sierra_Chart_Days[CHR-117] The number of distinct days in the current level where the user placed at least 1 order on Rithmic that returned AppName = Sierra Chart. On Rithmic, AppName is only ever returned at the point an order is placed — there is no concept of reading AppName from a held position or a bare login with no order. If the user placed orders on 2 platforms the same day, including Sierra, that day still counts as a Sierra_Chart_Day as long as at least 1 of that day's orders returned AppName = Sierra.
Total_Active_Trading_Days[CHR-117] The number of distinct days in the current level where the user placed at least 1 order on Rithmic, on ANY platform (not just Sierra).

Superseded wording (pre-2026-10-30): the prior draft defined Total_Active_Trading_Days as "a day the trader logged into the platform and established a connection to the server" (general login/connection, not order-gated) and left ambiguous whether held-position days without new orders should count toward Sierra_Chart_Days. The client explicitly rejected both: do not track held positions or general Rithmic logins — gate both numerator and denominator on "placed at least 1 order," full stop.

(2) If Payout_Ratio >= 0.5: calculate the final amount:

Final_Amount = Ceiling(Days in Level / 30) * $35.00

Push the calculated amount to the Dots API (Contractors and International traders) or Rippling API (W-2s - US traders from level 6 to above):

TriggerActionImpacted UC_ID
Level progressionTotal_Payout = Level_Performance_Bonus + refundable_amount (from market data) + final_amount (Sierra Chart). Update the SQL payouts table record for this promotion event with amount = Total_Payout. This ensures that when Flow 5 picks up this payout ID, it processes the full amount (Bonus + Refund) automatically.UC_8.1.1 (promotion trigger)
Hard breachPush the calculated amount to the Dots API or Rippling API.UC_4.15.2 (hard breach trigger)
SIM to LivePush the calculated amount to the Dots API or Rippling API.UC_5.1 (go-live trigger)

Example: 10 days / 30 = 0.33 → Ceiling = 1 → (1 × $35 = $35).

45 days / 30 = 1.5 → Ceiling = 2 → (2 × $35 = $70).

[CHR-117 — client confirmation, 2026-10-30] (2a) Reaching two levels within the same calendar month — paid twice, NOT blocked. If a user reaches Level 3 on, say, 1/10 and Level 4 on 30/10, each level progression independently triggers its own Reimbursement calculation (Step (1)–(2) above) scoped to that level's own Days_in_Level/Sierra_Chart_Days/Total_Active_Trading_Days window — this produces 2 separate Final_Amount payouts in the same calendar month. This is confirmed intentional, not a bug — do not add logic to detect or block a second same-month payout, and do not collapse the two Final_Amount calculations into one. The client explicitly accepted paying 2x in this scenario as currently specified.

⚠️ Conditional cap — not yet in scope, requires a separate CR. The client separately noted they are open to capping total Sierra Chart reimbursement at $35/month (i.e. suppressing/reducing the second same-month payout so the user never nets more than $35 in any calendar month), but said this would need its own formal Change Request before being implemented. Until that CR is raised and approved, the uncapped 2x-payout behavior above is the confirmed behavior — BA should not build a cap speculatively.

(3) If Payout_Ratio < 0.5: trigger the Sierra_Reimbursement_Denied email via AWS SES:

"Our connection logs indicate that Sierra Chart was not your primary execution terminal during this period (Used [Sierra_Chart_Days] out of [Total_Active_Trading_Days] active days). As a result, the platform reimbursement has been declined."

Out-of-scope: Stack Trading does not need to verify if users have paid for Sierra Chart or not. Stack Trading does not need to charge the user a Sierra Chart fee (reimbursement only) — users go directly to sierrachart.com to purchase their own license, and Stack Trading is not involved in that transaction.

19.3 [CHR-129] Quantower — License Validation Endpoint POST /api/license

Affected UC: UC_2.7-2.8.

The flow is inverted — Stack Trading hosts an endpoint for Quantower. When the user opens Quantower and tries to connect, Quantower pings Stack Trading's endpoint to ask "Is this user authorized?" The middleware checks the database, and if platform_selection == 'Quantower', returns an approval response. (Quantower API spec: api.quantower.com.)

/api/license

Request:

{ "username": "User@emaildomain.com", "provider": "Quantower" }

Response:

{ "allowed": true }
CriterionRule
Data sourceStack Trading's user table — contains the trader's chosen charting platform.
AuthenticationHeaderx-api-key. Keys must authenticate or validate (Auth0, or another secure method).
Key managementKeys must be managed by Stack Trading — rotated, with a way to rotate the key. Prefer a static key provided to vendors (not a short-lived token).
Key scopeKeep this simple, data-driven, and dynamic — the schema{ username, provider } → { allowed: true/false } must not be scoped so narrowly that it only works for Quantower; it must also work for other vendors (e.g. Sierra Chart, which the client intends to propose this same endpoint for).API Keys should be given scope. Meaning if we create the API key for Quantower and they attempt to query for ATAS we can return 403 Forbidden
Email matchingCase-insensitive.
Provider matchingCase-insensitive. Theprovider field allows any provider input.
No matchDo not return more data than given. If the email or the provider does not match the query, the return isfalse.
HTTP status — wrong key401.
HTTP status — valid key, wrong scope403 — reserved for proper auth but lack of permissions.
Rate limitingLimit calls/minute allowed to a reasonable amount (15 calls per 10 seconds)
IP restrictionBlacklist model (not whitelist). Infrastructure-level enforcement — not application level — so it can be updated and maintained without requiring a deployment. List starts empty — all IPs are allowed by default. Ops manually adds any abusive IP to the blacklist to block it.

19.4 [CHR-130] MotiveWave + ATAS — B2B License Provisioning

Affected UC: UC_2.7-2.8.

The middleware makes a separate, subsequent API call directly to the ATAS or MotiveWave B2B API to automatically generate a charting license/account for the user. The dashboard then displays both the Rithmic credentials and the newly generated platform license, IF applicable.

Impact on UC_2.8.3 / UC_2.8.4

This B2B license call always runs as step 2, after Rithmic account creation (step 1), in parallel with Auth0 account creation:

Create Rithmic account
  → then, in parallel: Auth0 account creation  +  3rd-party platform (ATAS/MotiveWave) license call
     - Auth0 fails OR Rithmic fails  → HALT (existing behavior, unchanged — Ref: UC_2.8.3 §5 / UC_2.8.4 §6)
     - Platform license call fails   → PROCEED normally (does NOT halt, does NOT block checkout/login)

3rd-party platform account creation failure never stops provisioning:

  • The existing 2-way gate in UC_2.8.3 §4 step 6 / UC_2.8.4 §5 step 4 (Auth0 + SIM/Rithmic) is unchanged — it stays the only hard gate on the "Setting up your trading floor" interstitial. The B2B license call (CHR-130) is explicitly not added as a third blocking condition.
  • If the ATAS/MotiveWave B2B API call fails: retry 3 times, then stop retrying and treat as failed. The user still completes checkout and still reaches login/Dashboard normally with Rithmic credentials — Rithmic account is not rolled back.
  • The trader is notified by email that the issue has been escalated to Ops. Ops is notified via Slack with full account-creation details for the specific platform, so an Ops member can create it manually and email the trader once done.

Slack alert — Platform License Provisioning Failed (Ops)

FieldValue
TriggerATAS/MotiveWave B2B license API call fails after 3 retry attempts
Channel#ops-general — C0BR8LRC5MK (Prod) · #test-ops-general — C0BR6UXRR8D (Test)  
MessageSee the two message templates below (one per platform).
Additional actionOps creates the account manually on the vendor's portal, then emails the trader once complete (no system-automated completion email for this step — manual)

Slack message template — MotiveWave:

⚠️ Platform License Creation Failed: Trader [Trader_ID] / [Trader_Email] — Platform: MotiveWave.
Rithmic account created successfully; MotiveWave license call failed after 3 attempts. Manual account creation required.

Details:
• Partner: [Partner_Code]
• Partner password: [Partner_Pwd]
• Email: [Trader_Email]
• First name: [First_Name]
• Last name: [Last_Name]
• Lease period (months): [Lease_Period_Months]
• Service: Rithmic

Slack message template — ATAS:

⚠️ Platform License Creation Failed: Trader [Trader_ID] / [Trader_Email] — Platform: ATAS.
Rithmic account created successfully; ATAS license call failed after 3 attempts. Manual account creation required.

Details:
• Login (email): [Trader_Email]
• Password: [Auto_Generated_Password] (also emailed to trader separately)
• Stack Trading account ID: [Stack_Trading_User_ID]
• Region (country, full name): [Trader_Country]
• Land (country, full name — same as Region): [Trader_Country]
• Autorenewal: 1

Email — SES-48 (new)

FieldValue
Email IDSES-48
Template KeyPlatform_License_Provisioning_Failed
TriggerSame as the Slack alert above — ATAS/MotiveWave B2B license call fails after 3 retries. Fired to the trader at the same time as the Ops Slack alert
RecipientTrader whose platform_selection is ATAS or MotiveWave and whose license call failed
UC ReferenceUC_2.7-2.8 (CHR-130)

Full Email:

Subject: Action Needed on Your [platform_selection] License — Our Team Is On It

Header: We Hit a Snag Setting Up Your [platform_selection] License, [First Name].

Body:

We weren't able to automatically generate your [platform_selection] charting license during setup.

Our Operations team has already been notified and is setting up your [platform_selection] license manually. You'll receive a follow-up email with your license details as soon as it's ready.

No further action is needed on your end right now.

If you have any questions in the meantime, contact support@stacktrading.com.


Footer: Stack Trading | support@stacktrading.com

19.5 TradeSea — Guide Only

There is no custom API integration required. The only thing needed at this time is the guide.


CR-20: is_default Payment Card Write Scope

Applies to every flow that takes a payment from the trader through a Change Payment Method / Change Payment Card modal or a 1-Click/Secure Checkout purchase — i.e. Market Data subscription billing (UC_4.17.1) and one-off transactions: Reset, Re-Buy, Time Extension (UC_4.10.3, UC_4.10.4, UC_4.15.3). This CR governs when is_default is written.

20.2 Market Data Change Payment Method modal — always writes is_default

Triggeris_default write
Trader selects or adds a card in the Market Data Change Payment Method modal, then confirms (Done)Set is_default = true on that card. Ref: UC_4.17.1 §5.6 step 30
Trader selects Alternative Payment Method in the same modal, then confirmsClear is_default = null on every saved card. Ref: UC_4.17.1 §5.9

20.3 Reset / Re-Buy / Time Extension

CriterionCaseRule
Scope—Clicking Change Payment Method / using 1-Click / Secure Checkout Fallback during a Reset, Re-Buy, or Time Extension purchase. This is a one-off transaction for that specific purchase only.
Case A — no card ever saved beforeTrader has never saved any card at all (no vaulted card exists — e.g. they originally checked out with APM and this is the first card they've ever added) and pays this one-off purchase with a credit cardThe newly added card is saved as is_default = true
Case B — any card already saved, regardless of current is_defaultTrader already has at least one saved card — whether one of them is is_default = true, or all of them are is_default = null because none was ever marked defaultDo not write to is_default at all, no matter which payment method is used to pay. A newly added card, if any, is saved  normally but is never marked is_default. The existing is_default state is left exactly as it was before the purchase.

CR-21: Admin BPS Operations — General Rules (Shared)

Applies to every Admin BPS endpoint (Business/Platform Support endpoints called by Stack Trading's internal Ops/Admin team via the internal BPS UI at bps-admin.stacktrading.com.

21.1 Common payload shape & required fields

Every Admin BPS POST endpoint that modifies a trader account carries this common envelope.

{
  "user_id": "usr_uuid_12345678",
  "admin_id": "admin@stacktrading.com",
  "reason": "Trader platform preference change request",
  "transcript_url": "https://stacktrading.freshdesk.com/agent/tickets/99897"
}
FieldRequiredSource / Rule
user_idYesTarget trader's ID.
admin_idYesPassed explicitly in the payload by the BPS UI, or extracted server-side from the Admin's validated Auth0 JWT (Admin's Auth0 ID).
reasonYesFree-text justification, typed by the Admin in the BPS UI (e.g. "Trader platform preference change request"). Not a dropdown/enum — Admin writes it themselves.
transcript_urlYesDirect URL link to the existing Freshdesk ticket or Discord/Slack support thread that authorized this action — pasted by the Admin, not auto-generated (see §21.1.2).

The middleware must reject the request with HTTP 400 Bad Request if reason or transcript_url is missing or fails validation below — regardless of which specific Admin BPS endpoint is called.

21.1.1 reason field validation

  • Mandatory text field, validated at the DTO Validation layer (reject with HTTP 400 if missing or invalid).
  • Must contain at least 3 non-whitespace characters after trimming.
  • Maximum 1,000 characters.
  • Reject strings that contain only whitespace.

21.1.2 transcript_url field validation & no auto-ticket creation

  • Validated at the DTO layer (HTTP 400 on failure): must be a valid https:// URL, maximum 2,048 characters.
  • Not restricted to freshdesk.com — Admins may also paste Discord or Slack thread URLs. Any valid https:// URL is accepted.

21.2 Admin identity & role source — Auth0 JWT, not database

  • Do NOT add admin role columns (admin_LV1 / admin_LV2 / system_admin or similar) to the trader-facing Users table.
  • Per [CHR-52], Stack Trading employees authenticate via Google Workspace SSO in Auth0, which injects their role (Level_1, Level_2, or Admin) into the JWT custom claims.
  • The middleware must validate the Admin's role directly from the Admin's Auth0 JWT token on every Admin BPS call.
  • admin_id logged anywhere (payload, BPS_Audit_Log, etc.) is the Admin's Auth0 ID, extracted from their validated Auth0 JWT.

21.4 Ops tooling — no dedicated Admin BPS Console UI in scope

  • The Admin BPS Console UI itself is out of scope for SotaTek's delivery. Stack Trading's own team (Adam) has already built the internal BPS UI at bps-admin.stacktrading.com and is waiting on the backend endpoints to connect to.
  • SotaTek's scope for this endpoint family is limited to: secured REST endpoints (validating payload per §21.1, Admin role per §21.2) + Swagger/Postman documentation for Stack Trading to wire up on their side.

21.5 Support Action Audit Trail — immutable BPS_Audit_Log

Per the V7 Prop Tech BPS specification: all administrative overrides executed via a Support Screen must be written to an immutable PostgreSQL audit table. The record must include: Admin ID, User ID, Action Type, Timestamp, Reason, and Transcript URL.

  • Admin ID — see §21.2 (Auth0 ID from the Admin's validated JWT).
  • User ID — the target trader's user_id.
  • Action Type — not an input parameter sent by the Admin. Each BPS endpoint automatically writes its own action name — a standard VARCHAR string, not a database enum — into BPS_Audit_Log when called. Full list of Action Type values:
    • ADMIN_PLATFORM_REASSIGNMENT
    • ADMIN_POD_REASSIGNMENT
    • ADMIN_HARD_RESET
    • FORCE_SESSION_KICK
    • REDUCE_PROFIT_TARGET
    • INJECT_GOODWILL_EQUITY
    • OVERRIDE_TIME_EXTENSION
    • SEND_GOODWILL_MERCH
    • ISSUE_REFUND
    • RESEND_RTRADER_INSTRUCTIONS
    • RESEND_WELCOME
    • TRIPLE_A_CRYPTO_RESCUE
    • REVOKE_POD_LEADERSHIP
    • TERMINATE_POD_LEADERSHIP
    • RESET_VERIFF_KYC
    • OVERRIDE_KYC_EXCEPTION
    • APPLY_PAYOUT_HOLD
    • ESCALATE_TO_L2
    • IMPERSONATE_USER
    • PROVISION_IN_HOUSE_TRADER
    • MANUAL_PROMOTION
  • Timestamp — per CR-08 (UTC / ISO 8601).
  • Reason — see §21.1.1.
  • Transcript URL — see §21.1.2.

21.6 Action Type ↔ UC_ID mapping

Maps each Action Type to its owning UC (Stage 10 — Admin / BPS Operations).

Action TypeUC_ID
ADMIN_PLATFORM_REASSIGNMENTUC_10.4.4 (Admin Platform Reassignment)
ADMIN_POD_REASSIGNMENTUC_10.3.1 (Admin Pod Reassignment)
ADMIN_HARD_RESETUC_10.4.1 (Admin Hard Reset)
FORCE_SESSION_KICKUC_10.4.2 (Force Session Kick)
REDUCE_PROFIT_TARGETUC_10.2.1 (Reduce Profit Target)
INJECT_GOODWILL_EQUITYUC_10.2.2 (Inject Goodwill Equity)
OVERRIDE_TIME_EXTENSIONUC_10.2.3 (Override Time Extension)
SEND_GOODWILL_MERCHUC_10.1.8 (Send Goodwill Merch)
ISSUE_REFUNDUC_10.4.3 (Issue Full Refund — Account Kill)
RESEND_RTRADER_INSTRUCTIONSUC_10.2.5 (Resend R|Trader Instructions)
RESEND_WELCOMEUC_10.2.9 (Resend Welcome / Claim Email)
TRIPLE_A_CRYPTO_RESCUEUC_10.2.6 (Triple-A Crypto Rescue)
REVOKE_POD_LEADERSHIPUC_10.3.2 (Revoke Pod Leadership)
TERMINATE_POD_LEADERSHIPUC_10.3.3 (Terminate Pod Leadership)
RESET_VERIFF_KYCUC_10.2.7 (Reset Veriff KYC)
OVERRIDE_KYC_EXCEPTIONUC_10.4.7 (Manual KYC Exception Override)
APPLY_PAYOUT_HOLDUC_10.4.6 (Manual Payout Hold)
ESCALATE_TO_L2UC_10.2.8 (Escalate to L2)
IMPERSONATE_USERUC_10.5 (Admin Impersonation)
PROVISION_IN_HOUSE_TRADER❌ — not identified in the current UC_10.x list. Day 2 item  
MANUAL_PROMOTION❌ — not identified in the current UC_10.x list. Day 2 item

CR-22: Reset Time & Market Closed Definition — Futures vs. Forex (Shared)

22.1 Reset Time — Definition & Anchor per Asset Class

reset_time (roll-over) is the fixed daily clock boundary at which a Soft Breach soft-lock auto-unlocks and the Daily P&L counter resets.

CriterionFuturesForex
AnchorFixed daily wall-clock literal — 18:00 ET (18:00 EST in winter / 18:00 EDT in summer), every day.   Fixed local wall-clock instant — 17:00 ET (17:00 EST in winter / 17:00 EDT in summer), Monday–Friday.
DST (EST/EDT) resolution mechanismSource-native — resolved upstream by the CME Reference Data API itself when it publishes that day's Official_Close_UTC/Session_Open_UTC; no application-side DST logic.Timezone-library-native — backend resolves the America/New_York IANA zone's local 17:00 every day (e.g. Intl/date-fns-tz/luxon); the zone's own EST/EDT transition dates yield the correct UTC instant automatically, no hardcoded offset or manual transition-date table.

Full mechanism detail (applies identically everywhere this UTC instant is consumed — UC_6.1.1, UC_6.1.2, UC_6.1.3, UC_4.1.3): UC_4.1.3 BR_4.1.3.5. Every downstream UC consumes the already-resolved UTC instant — none re-implements EST/EDT offset math itself.

22.2 Market Closed Definition — Futures (CME Cronjob-Driven) vs. Forex (Fixed Weekly Window)

"Market closed" is asset-class-specific and is never a locally-hardcoded assumption

CriterionFuturesForex
Authoritative sourceMust be driven by the CME Reference Data Ingestion cronjob (UC_6.1.1) — a single daily cron @ 01:00 UTC that pulls CME's published trading calendar (GET /v3/tradingHours, GET /v3/productDetails) per whitelisted symbol and writes Session_Open_UTC/Official_Close_UTC/Halt_Start_UTC/Halt_End_UTC into CME_Instrument_Details Fixed weekly window, not exchange-driven. Confirmed close edge: Friday 17:00 ET — same institutional rollover instant as the daily reset_time (§22.1)

CR-23: Pod Status Lifecycle — Mentee & Pod Leader (Shared)

Single reference for every pod status of a mentee and of a Pod Leader: when a status is entered, what it blocks, what it keeps, and what moves it to another status. Owning UCs: UC_8.2.1 (Flow 10), UC_8.2.8 (Flow 11), UC_8.2.9 – UC_8.2.13 (Flow 15A–15C, 17), UC_4.14.2 (My POD card), UC_4.17.1 (Flow 12), UC_10.3.2 / UC_10.3.3 (BPS Revoke / Terminate). When a UC and this CR differ, the owning UC's latest version wins and this CR must be updated.

23.1 Mentee — pod_status

  • pod_status is stored in its own column, separate from the trading account state users.status, so the two never overwrite each other.
  • Only LIVE Level 1–6 traders can be mentees. SIM / Evaluation never join a pod. From Level 7 a trader is never a mentee again.
  • A trader counts as in the waitlist when pod_status is Waitlist, Inactive_Hold or Pending_Pod_Confirmation.
  • Join_Date is the date the trader entered the waitlist (queue order, FIFO). It is not pod_join_date (the date the trader joined a pod). Entering the waitlist does not change pod_join_date.
StatusEntered whenBlocked fromKeepsMoves to another status when
null (in no pod)Never joined: live onboarding completed, Pod_Mentorship_Invite email receivedLeft: account Terminated (LIVE) or Failed (SIM) after Hard Breach or Resign (Flow 7) · reached Level 7 · rejected when clicking the confirmation link❌ No leader, no Discord pod channel, no Trading Plan deadline❌ A trader who left is removed from the Discord channel; pod_leader_id and pending SLA deadlines are cleared✅ A trader who never joined sees [Join a POD]✅ A Level 7 trader who accepts the leader role gets their own podSubmits the Style form, a leader has a spot → AssignedSubmits the Style form, no spot → WaitlistTerminated / Failed or Level 7+: stays null, cannot join again
AssignedFlow 10 direct match (same Asset_Class required, same Style preferred, then the pod with the fewest mentees) · clicks the confirmation link within 48h · returns from Inactive_Hold and the matching finds a leader · Flow 15A re-matches to a new leader❌ Cannot change or leave the pod by themselves (Support → Ops POST /admin-pod-reassignment, 30-day cooldown)❌ Cannot resubmit the Style form❌ Trading Plan is submitted once only❌ Discord not linked → My POD card stays on Link Discord to Unlock✅ Leader, members, Discord channel, Pod Member role✅ Trading Plan analysed by AI and sent to the leader✅ On a pod change, the existing Trading Plan is reused30 days without trading → Inactive_HoldLeader Suspended / Terminated and no other leader found → WaitlistTerminated / Failed or reaches Level 7 → nullOps reassigns the pod → stays Assigned
WaitlistSubmits the form with no spot · loses the leader and Flow 15A finds no match · Inactive_Hold trader who was in a pod reactivates with no spot · clicks the link but the leader is no longer Active and no other match → end of the queue (Join_Date = time of entering the waitlist)Inactive_Hold trader who was waiting reactivates → keeps the original Join_Date❌ No leader, no pod channel❌ Cannot resubmit the Style form❌ A submitted Trading Plan gets no AI analysis, no SLA, no webhook to a leader❌ No queue position or estimated wait shown✅ Queue position (FIFO by Join_Date), no expiry✅ Trading Plan PDF kept on S3 and reused once assignedFlow 11 invites → Pending_Pod_Confirmation30 days without trading → Inactive_HoldTerminated / Failed or reaches Level 7 → null
Pending_Pod_ConfirmationA spot opens (mentee leaves, new leader, Ops raises Max_Capacity, leader Suspended → Active) and Flow 11 selects the trader❌ Link is single-use and expires after 48h❌ Not invited again; cannot resubmit the form❌ Dashboard shows no invitation, button or countdown✅ The spot is held for the trader (Current_Count already increased)Clicks within 48h → AssignedClicks, leader no longer Active, no other match → Waitlist (end of the queue)Clicks but is Terminated / Failed or Level 7+ → nullNo click within 48h, or caught by Flow 12 before clicking → Waitlist_Ghost
Waitlist_GhostNo click within 48h · caught by Flow 12 (30 days without trading) while waiting to click❌ Removed from the queue, loses the old Join_Date✅ Treated as never joined: My POD card shows [Join a POD] againResubmits the form, a spot exists → AssignedResubmits the form, no spot → Waitlist (end of the queue)
Inactive_Hold30 days without placing an order (Flow 12 Zombie Protocol): market data paused; a trader in a pod releases the spot❌ Removed from the pod member list❌ Skipped when Flow 11 selects a trader❌ Cannot resubmit the Style form✅ A waiting trader keeps the waitlist record and Join_Date✅ SLA deadlines are paused, not lostReactivates market data, was in a pod, matching finds a leader → Assigned (no priority for the old pod)Reactivates, was in a pod, no spot → Waitlist (end of the queue)Reactivates, was waiting → Waitlist (previous position)

Not a pod status: a trading account Locked for DTO / Hiatus (Flow 13). A waiting trader is skipped by Flow 11 but keeps Join_Date. An Assigned trader stays in the pod. SLA deadlines are paused.

23.2 Pod Leader — Pod_Leader_Registry.Status

  • Flow 10 and Flow 11 match mentees only to a leader whose Status is Active.
StatusEntered whenBlocked fromKeepsMoves to another status when
ActiveOpts in via Flow 15B · or Founding Mentor created via Flow 1.5Nothing✅ Receives mentees (Flow 10 / 11, while Current_Count < Max_Capacity)✅ Carry accrues and vests monthly (Flow 17)✅ Discord role and channel pod-[leader_name]✅ Founding Mentor has a Workspace accountDTO / Hiatus leave (Flow 13) → On_LeaveDrawdown Defense (Flow 4B) or BPS Admin sets it manually → SuspendedAccount fails or resigns (Flow 7) or BPS Terminate → TerminatedBPS Revoke → Permanently_Ineligible
On_LeaveLeader takes DTO / Hiatus leave via Flow 13❌ Receives no new mentees (Flow 10 matches Active only)❌ SLA timers paused❌ No Acting Cover; mentees are not re-matched✅ Keeps pod, mentees, Pod Leader role, pod channel, Workspace (still receives the Wednesday AI Brief)✅ Carry still accrues and vests✅ POD_LEADER_TERMINATED / Flow 15C is blocked during the leaveFlow 13 Return Protocol → Active
SuspendedFlow 4B Drawdown Defense when is_pod_leader = True: account locked for 48h, then set to Suspended · or BPS Admin sets it manually (UC_8.2.9 Trigger A)❌ Pod dispersed; mentees re-matched via Flow 15A❌ During the 60-day PIP (stagnation_deadline = Today + 60d): no mentees, no opt-in, no pod activity❌ Carry frozen✅ Carry is not lost; kept until the leader returns to ActivePasses the PIP and opts in again via Flow 15B → Active (stagnation_deadline = Today + 90d)Fails the PIP → Terminated (carry lost)BPS Revoke → Permanently_Ineligible
TerminatedFlow 7 Condition B: the leader's account fails or resigns · or BPS Terminate (UC_10.3.3, only while Active) → Flow 15C cascade❌ Loses the Pod Leader role (Discord and DB); pod channel archived❌ Mentees re-matched or sent to the waitlist❌ Pending_Carry_Balance = 0 (carry lost)❌ Founding Mentor's Workspace @stacktrading.com is suspended✅ BPS Terminate only: SIM / LIVE account unchanged; the leader left the role in good standing and can be invited againBPS Terminate only: Flow 4 invites again, opts in via Flow 15B → Active
Permanently_IneligibleBPS Revoke (UC_10.3.2, Level 2 Admin / System Admin only) while the leader is Active or Suspended (Flow 15 Trigger C)❌ Loses everything as in Terminated (role, channel, mentees, carry = 0)❌ Permanent blacklist: Flow 4 does not invite, Flow 10 does not match, Flow 15B refuses opt-in✅ SIM / LIVE account unchangedNone (final state)

Glossary

TermDefinition
TraderParticipant in the evaluation program; if targets are met, receives real capital allocation
PnL (Profit and Loss)Trader's profit or loss metric
EquityCurrent net worth = Starting Balance + Floating P&L. Distinct from Balance (settled)
DrawdownCapital decline — % loss from the highest point ever reached. Primary risk metric
Daily Loss LimitMaximum permitted loss in one trading day. Breach → Soft_Breach (trading suspended until day reset)
Max Drawdown / Level StopMaximum cumulative loss limit. Breach → account permanently closed (Hard Breach)
Profit TargetRequired profit level for a trader to pass the evaluation
Soft BreachMinor violation (Daily Loss Limit hit). Trading temporarily suspended; account remains open
Hard BreachSevere violation (Max Drawdown hit). All positions liquidated; account permanently locked
Flatten / LiquidateClose all open positions, returning account to a "flat" (no open orders) state
Trim (Partial Position Reduction)Close a portion of a position (not all) to reduce risk
TRIM_TO_COMPLIANCEAutomated algorithm: when risk threshold is exceeded, iteratively close largest positions until portfolio is within safe limits
Atomic Kill SwitchEmergency shutdown — 4 sequential steps: (1) lock new orders, (2) close all positions, (3) cancel pending orders, (4) update DB → status "Failed"
MarginMinimum capital required to hold positions overnight
DMA (Direct Market Access)Order routing mechanism that sends orders directly to the real exchange without intermediaries
FCM (Futures Commission Merchant)CFTC-licensed broker for Futures contracts. Ironbeam is Stack Trading's FCM
Omnibus AccountMaster account held under the company name at the exchange, containing individual trader sub-accounts
KYC (Know Your Customer)Mandatory identity verification process before live capital allocation, for AML/fraud prevention
W-8BEN / W-9US tax forms: W-9 for US citizens, W-8BEN for non-US persons
CarryCommission earned by a Pod Leader from the profits of their Pod members
PodTrading group — one leader plus multiple members sharing a trading style
WORM (Write Once, Read Many)Immutable storage mechanism: once written, data cannot be modified or deleted
Immutable LedgerImmutable on-chain record — data written to Polygon PoS blockchain; no one can alter payment history
W-2 EmployeeOfficial US employee with a fixed-term contract, salary, benefits, and paid time off
International ContractorNon-US collaborator; receives compensation via Dots (not US payroll)
RipplingHR and payroll management software — automates employee onboarding, tax calculation, and salary disbursement
DTO (Days Time Off)Paid Time Off
Evaluation PackageTrader evaluation tier — 3 options: Associate Track (EVAL_L1 / $650 / $25k notional), Accelerated Associate Track (EVAL_L2 / $1,250 / $50k notional), Advanced Associate Track (EVAL_L5 / $4,500 / $150k notional)
Founder Cohort"Founding 500" program — first 500 registrants purchase at a permanently locked price (no market increases)
Reset TokenToken allowing a failed trader to reset their Sim account to Day 1, keeping their tier. Cheaper than a new purchase
Re-BuyWhen a trader fails on a Live account (Level 1+), they must purchase a new Challenge to restart from Level 0. Price = Challenge Price × (1 − Retry_Discount)
Defense ProtocolProtection for Level 9+ traders who hit Level Stop — instead of immediate termination, they enter a 48-hour cooling-off period, then trade again with reduced parameters (capital ×0.25, target 6%, stop 5%)
Flow A–JCheckout geo-routing system by country: A=USA/default, B=UK/AU, C=EU/EEA, D=Quebec (French UI), E=UAE, F=Sanctioned (block 403), G=India, H=Philippines, I=Brazil, J=South Africa
NMIPrimary payment gateway — processes Credit Card, Apple Pay, Google Pay via Collect.js iframe (PCI compliant)
RithmicFutures gateway — Level 0 uses Paper Trading Gateway (sim); Level 1+ uses Live FCM Gateway (Ironbeam)
TraderEvolutionPrimary Forex platform — provides Admin API for account management and equity monitoring
YourBourse BridgeFIX routing bridge — routes orders from TraderEvolution/MT5 to Forex.com and Interactive Brokers
ZapierAutomation bus — orchestrates 40+ operational flows (provisioning, promotion, termination, billing, payout, etc.)
The Desk Manager / GEKKOAI commentary engine (Gemini 1.5 Flash 8B) — plays the role of Gordon Gekko, auto-commenting on trader actions across 15 event types. Rate limit: 10 critiques/hour/user
Zapier Tables A–JGlobal configuration variables stored in Zapier: Table C (global vars), Table D (email templates), Pod_Leader_Registry — native PostgreSQL table, not a live Zapier Table (name retained for cross-reference to the original RFQ "Table E" section only), Table F (Defense Matrix), Table G (Discord roles), Table H (Perks Registry), Table I (Platform Registry), Table J (Pricing)
UTCCoordinated Universal Time — standard for all system timestamps, expiration metrics, and database entries. See CR-08
NuveiPayment gateway for LatAm (Brazil, Colombia, Mexico) — replaces EBANX per CR-20260720-002
EverflowAffiliate/velocity tracking platform — replaces Impact.com per CR-20260720-003
TradeSeaTrading platform — replaces NinjaTrader per CR-20260720-001
FreshdeskSupport ticketing system — replaces Zendesk per CR-20260720-004

Changelog

DateVersionUpdated itemBeforeAfterNotes
2026-07-26v1.1Initial document—CR-01–CR-11 + GlossaryInit version.
2026-07-30v1.2New CR-12 — UTM Attribution CaptureNo global cross-cutting UTM rule existed; UTM capture logic was defined locally inside UC_2.1.1 (BR_2.1.1.4) as session-state + first-seen-wins, scoped to the checkout page onlyAdded CR-12: global root-layout execution (site-wide, not checkout-only) +localStorage persistence + last-touch (overwrite-on-presence) attribution + payload injection at Partner Application / Waitlist / Checkout Step 5. Supersedes BR_2.1.1.4's storage/attribution mechanism.CR-20260730-002; Adrian Stack (Slack, 2026-07-30)
2026-08-06v1.3CR-09 §9.2 — Phone Number Field: Input structureTwo-part field: [Country flag + Dial code] (prefix, left) and [Number input] (right)Two-part field: [Dial code selector] (prefix, left) and [Number input] (right) — Removed unsourced "Country flag" component; no source confirms flag UI element.
2026-08-08v1.4New CR-13 — Rounding to 2 Decimal PlacesNo shared rounding rule existed; UC_4.10.1 referenced CR-11 (display format) for its rounding logicAdded CR-13: round-half-up to nearest hundredth using the code language's native rounding function, applies to computed values likeDaily_Loss_Limit/Net_P&L. UC_4.10.1's BR_4.10.1.1 now cites CR-13 for the rounding algorithm (CR-11 remains for display formatting only)STAGE2-031; QN-4.10.1-02/04
2026-08-10v1.5New CR-14 — WebSocket Reconnection Resiliency (Shared)Rule lived only as UC_4.2.1 §BR_4.2.1.4, a single-widget BR referenced by 4 sibling UCs (4.2.2/4.2.3/4.2.4/4.2.5) and 4 external UCs (4.3/4.4/4.8.1/4.8.2)Moved to CR-14 (generalized to any WS-fed Dashboard widget); UC_4.2.1's BR_4.2.1.4 removed, all 8 cross-reference points repointed tocommon_rules.md#cr-14-websocket-reconnection-resiliency-sharedUser request — UC_4.2.1-4.2.5 batch edit
2026-08-20v1.6CR-02 §2.2 — Default Length Limits: added Promo code input rowTable only listed Textbox (255), Textarea (500), Search box (255) — Promo code input's 100-char block limit existed only locally in UC_2.7-2.8 §5 Screen Description Row 1, not in the shared tableAdded row: Promo code input — 100 chars, Block (character 101 cannot be entered, no message shown), matching UC_2.7-2.8's existing field-level specUser request
2026-08-31v1.7CR-14 renamed "WebSocket Reconnection Resiliency" → "WebSocket Reconnection & Snapshot Resiliency"; added Backend snapshot persistence / Market-closed behavior / Page reload (F5) behavior rowsCR-14 only covered mid-session reconnection (widget retains last-known values while reconnecting) — did not cover backend snapshot persistence for reload, market-closed state, or F5 behaviorExtended to: (1) Backend maintains latest snapshot per widget so reload restores immediately instead of rendering empty; (2) market-closed → keep showing latest snapshot until new data arrives; (3) F5/reload → render from snapshot first, then apply subsequent WS events on topUser instruction (BA session) — applies to all UCs referencing CR-14 (UC_4.2.1-4.2.5, UC_4.3, UC_4.4, UC_4.5.1, UC_4.5.2, UC_4.6.1-4.6.4, UC_4.8.1, UC_4.8.2, UC_4.12.1, UC_4.12.2, UC_4.12.4, UC_4.12.6, UC_4.13)
2026-08-25v1.7New CR-15 — Reference (Email & Slack)Did not existAdded CR-15 with two sub-sections: CR-15.1 (5 operational email addresses) and CR-15.2 (Slack channel registry — 7 production channels + 4 development/test channels, each with channel ID and description)User request
2026-08-26v1.8CR-09 §9.2 — Phone Number Field: added "Submitted / stored format" rowTable only specified the two-part UI input (dial code selector + number input) and E.164 length (6–15 digits excluding dial code); no rule stated whether the dial code must be included in the value sent to the API / stored in DB — downstream UCs (e.g.UC_4.6.2_v1.md, IN-10) already assumed a combined E.164 string but CR-09 itself never said soAdded row: dial code + number are concatenated into a single E.164 string (e.g.+14155552671, no separator) before being sent in the phone_number payload / stored in DBUser request
2026-09-15v1.9New CR-16 — Net PnL Display, Full Precision (Whole Dollars), No AbbreviationRule lived only as UC_4.8.1 §BR_4.8.1.6 point 1 (framed as a one-off CR-11 exception for the PnL Gauge center value), reused verbatim by UC_4.12.2 via cross-reference; UC_4.7.5/UC_4.12.5 (Daily Loss Limit Bar) had no dollar-value display rule at all — pure %-fill progress barsAdded CR-16 (exact dollar amount, comma separators, cents omitted, never abbreviated — deliberate exception to CR-11's 2-decimal rule). UC_4.8.1 BR_4.8.1.6 point 1 and UC_4.12.2 BR_4.12.2.2 repointed to cite CR-16. Extended to UC_4.7.5/UC_4.12.5: new BR added to each introducing a Net PnL/remaining-limit dollar-value label, citing CR-16 — this UI element has no client source; added on explicit user instructionUser request — see UC_4.8.1, UC_4.12.2, UC_4.7.5, UC_4.12.5 Changelogs
2026-09-19v1.10New CR-17 — Soft Breach / Hard Breach Widget Data Display Behavior (Shared)No shared rule existed for how the 6 Overview-screen real-time widgets (Position Monitor Table, Pulse, Equity Curve, Profit Factor, Win Rate, PnL Gauge) display data during/after a breach — UC_4.10.1/UC_4.10.2 define breach trigger/lock/flatten mechanics only, not per-widget display behavior. UC_4.2.3 BR_4.2.3.4 (2026-09-15) additionally stated the Equity Curve's 30-min snapshot cron continued uninterrupted through Soft Breach, which conflicts with the new instruction belowAdded CR-17: Soft Breach — flatten/cancel still pushes immediate WS updates (widgets not frozen during the soft-lock window); snapshot-based widgets (Equity Curve) pause capture while the lock is active, resuming on the next tick afterreset_time auto-unlock; old data persists through unlock, new trading appends alongside it, consistent with Soft Breach having no archive/not being a failure. Hard Breach — WS updates stop once flatten/cancel completes and status = Failed; widgets freeze at last-received values; reset-to-Day-0 display only happens once a Reset/Re-Buy purchase provisions a genuinely new sub-account, never automatically. Supersedes the 2026-09-15 BR_4.2.3.4 wording that Soft Breach did not pause snapshotting — user confirmed override, 2026-09-19. UC_4.2.1–4.2.5 and UC_4.8.1 repointed to cite this CRUser instruction (BA session), 2026-09-19, relaying client requirement; conflict with prior BR_4.2.3.4 flagged and resolved via explicit user override — see UC_4.2.1-4.2.5, UC_4.8.1 Changelogs
2026-10-09v1.11New CR-18 — Inbound Webhook No-Op: 200 OK + Drop Payload (Shared)Did not exist — the "return 200 OK and drop" behavior was restated separately in UC_8.1.1 and across Pod System flows (QnAPOD-JOIN-16, POD-JOIN-20, POD-JOIN-21, POD-PLAN-09)Single shared rule; UCs reference CR-18BA approved in UC_8.2.8 Init Flow (QnA_init_docs P-01)
2026-10-12v1.11CR-18 — Known instances: UC_8.2.8 exampleUC_8.2.8 BR_8.2.8.5 — confirmation click that fails re-validationUC_8.2.8 BR_8.2.8.7 — duplicate pod confirmation clickClient round 3 (POD-WAIT-19): an invalid click is now rejected with a message and releases the seat — no longer a silent drop. Only the duplicate-click case stays under CR-18 (POD-WAIT-21)
2026-10-13v1.12CR-03 — new "Searchable" criterion[CHR-99]Dropdown rule had no search/filter requirement — only default state, long-text truncation, after-selection, re-open, and required-empty behaviorAdded: every dropdown renders a search/filter input inside the open option list, letting the user narrow visible options by case-insensitive substring match, regardless of option countClient supplement CHR-99 — "All Dropdown fields must allow to search." Applies globally (CR-03 is cross-cutting); no per-UC changes needed since every UC's dropdown fields already cite CR-03.
2026-10-14v1.14New CR-19 — Platform Provisioning & Third-Party Charting Platform Rules (Shared)No shared rule existed for platform provisioning sequencing — Zapier Flow 1 Step 3 described Rithmic-gateway platforms (TradeSea/Quantower/ATAS/MotiveWave/Sierra) as one flat IF-branch with no Rithmic-first ordering; no spec existed anywhere for an inbound license-validation API, or for Sierra Chart's BYOL disclaimer + usage-based reimbursementAdded CR-19: (1) Rithmic account provisioning always runs first for TradeSea/Quantower/ATAS/MotiveWave/Sierra Chart, platform-specific provisioning always runs after; (2)[CHR-117] Sierra Chart BYOL disclaimer + Payout_Ratio = Sierra_Chart_Days / Total_Active_Trading_Days reimbursement formula ($35/mo × Ceiling(Days_in_Level/30) if ratio ≥ 0.5, else Sierra_Reimbursement_Denied email); (3) [CHR-129] Quantower flow inverted — Stack Trading hosts POST /api/license, a vendor-agnostic {username, provider} → {allowed} endpoint secured by a static per-vendor x-api-key (scoped to provider, infra-level IP whitelist, 401 wrong key / 403 wrong scope); (4) [CHR-130] ATAS/MotiveWave get a separate B2B API call post-Rithmic; (5) TradeSea stays guide-onlyCHR-117, CHR-129, CHR-130
2026-10-14v1.15CR-19 §19.2 — "SIM to Live" reimbursement trigger: UC_ID corrected UC_5.8 → UC_5.1; UC_5.8 dropped from "Affected UCs" listTrigger table's "SIM to Live" row named UC_5.8 (go-live trigger); "Affected UCs" line included UC_5.8Platform entitlement (Rithmic + any platform-specific call) only ever happens once, at checkout (UC_2.7-2.8 / Flow 1 Step 3) — Flow 3H (UC_5.8) is Live account provisioning only and does not re-touch platform entitlement, so it has no CR-19 impact. The actual "SIM to Live" transition this trigger refers to is owned by UC_5.1 (Flow 3A). Corrected the trigger table row to UC_5.1 (go-live trigger) and removed UC_5.8 from Affected UCsUser correction, 2026-10-14 — UC_5.8 edit made earlier this session was reverted by user for the same reason
2026-10-17v1.16Glossary — "Zapier Tables A–J" row — Table E renamedTable E listed as "Table E (Pod Leader Registry)" alongside the other Zapier Tables, implying it is a live Zapier TableRenamed to Pod_Leader_Registry — native PostgreSQL table, not a live Zapier Table; name retained only for cross-reference to the original RFQ "Table E" sectionClient confirmation 2026-10-17 — PostgreSQL-only build instruction for Pod_Leader_Registry, restating POD-JOIN-02
2026-10-30v1.17CR-19 §19.2 [CHR-117] Sierra Chart — client correction on Sierra_Chart_Days/Total_Active_Trading_Days definitions + confirmation on same-month double payoutTotal_Active_Trading_Days was defined as "a day the trader logged into the platform and established a connection to the server" (general login/connection); left ambiguous whether held-position days without new orders count toward Sierra_Chart_Days; no rule addressed what happens when a user reaches 2 Levels in the same calendar monthBoth variables now explicitly order-gated: Sierra_Chart_Days and Total_Active_Trading_Days each count only distinct days in the current level where the user placed at least 1 order on Rithmic (numerator additionally requires that order to return AppName = Sierra Chart) — held positions and logins-without-an-order are excluded from BOTH sides, so holding a position for multiple days never hurts (or helps) the ratio. Added new point (2a): reaching 2 Levels in the same calendar month triggers 2 independent reimbursement calculations and is confirmed intentional (2x payout, not blocked) — a $35/month cap was raised as a possible future change but explicitly requires its own CR before being built.Client correction/confirmation relayed by user (BA session), 2026-10-30 — recommend opening a formal CR entry (e.g. CR-20261030-00X) in References/CR/_CR_INDEX.md for CR-20261014-001/CHR-117 since this is a correction to already-drafted CR-19 text, not a first-draft clarification
2026-10-30v1.18New CR-20 — is_default Payment Card Write Scope (Shared)No shared rule existed for when is_default gets written. UC_4.17.1 (Market Data), UC_4.10.3/UC_4.10.4 (SIM Reset/Re-Buy/Time Extension), and UC_4.15.3 (LIVE Reset/Re-Buy/Time Extension) all read is_default as a Gate 3 1-Click condition, but none specified the write-side behavior for one-off purchases — risk of a one-off APM/Crypto payment silently clearing the trader's recurring Market Data default, or a one-off card payment silently hijacking it.Added CR-20: Market Data's Change Payment Method modal always writes is_default (selecting a card → true; selecting APM → cleared) since that modal's whole purpose is managing the recurring default. Reset/Re-Buy/Time Extension (one-off transactions): Case A — trader has never saved any card at all and pays this one-off with a credit card → that card is saved as the new is_default, since there is no existing saved-card state to disturb. Case B — trader already has at least one saved card, regardless of whether is_default is currently true on one of them or null on all of them → paying with anything (saved card, APM, Crypto, or a new card) never writes is_default. UC_4.17.1, UC_4.10.3, UC_4.10.4, UC_4.15.3 should cross-reference this CR instead of re-stating is_default write logic locally.User instruction (BA session), 2026-10-30
2026-11-02v1.19New CR-21 — Admin BPS Operations General Rules (Shared)No shared rule existed for the common payload shape, field validation, admin identity source, or notification behavior across the Admin BPS endpoint family (Admin Platform Reassignment, Admin Hard Reset, Issue Refund, etc.) — each endpoint would otherwise redefine reason/transcript_url validation and admin-role sourcing independentlyAdded CR-21: (1) common payload envelope {user_id, admin_id, reason, transcript_url}, all 4 mandatory, HTTP 400 on missing/invalid; (2) reason — DTO-layer validation, ≥3 non-whitespace chars trimmed, max 1,000 chars, reject whitespace-only; (3) transcript_url — DTO-layer validation, valid https:// URL, max 2,048 chars, not restricted to freshdesk.com, and BPS endpoints do NOT auto-create a Freshdesk ticket (only Escalate to L2 calls the Freshdesk API) — Admin manually pastes an existing ticket/thread link; (4) Admin role/identity sourced from Auth0 JWT custom claims ([CHR-52]) — no admin role column on the trader Users table, admin_id = Auth0 ID/@stacktrading.com email; (5) notifications — standard Slack audit alert to #ops-general (routine, not SEV-1), trader email optional/Day-2; (6) Admin BPS Console UI itself is out of scope — Stack Trading's own bps-admin.stacktrading.com UI consumes SotaTek's REST endpoints + Swagger/Postman docsQnA relayed by user (BA session), 2026-11-02 — see References/QnA from clients/09_ADMIN_BPS_OPERATIONS/QnA_ADMIN_BPS_OPERATIONS.md (ADMIN-002, ADMIN-003, ADMIN-004, ADMIN-010 to ADMIN-012, ADMIN-015)
2026-11-03v1.20New CR-22 — Reset Time & Market Closed Definition — Futures vs. Forex (Shared)No shared rule existed — reset_time and "market closed" were each defined piecemeal inside UC_6.1.1 (CME cron/Dynamic Timekeeper), UC_4.1.3 BR_4.1.3.5 (DST handling), UC_4.10.1/UC_4.15.1 (Soft Breach unlock timing), and MT5_Plugin_Business_Logic_v1.md, with no single cross-reference point and no explicit statement that Futures "market closed" must be driven by the CME Reference Data Ingestion cronjob rather than a hardcoded assumptionAdded CR-22: §22.1 reset_time — Futures anchors to the dynamic Session_Open_UTC written daily by the CME cron (Ref: UC_6.1.1/CHR-76), Forex anchors to a fixed America/New_York 17:00 local wall-clock instant (21:00 UTC EDT / 22:00 UTC EST), Mon–Fri only, with Friday breaches holding the soft lock through the weekend until Monday's reset. §22.2 Market closed — Futures must be derived from CME_Instrument_Details as populated by the CME cronjob (Official_Close_UTC→next Session_Open_UTC, with Halt_Start_UTC/Halt_End_UTC as a distinct intraday maintenance state), falling back to the 14-day rolling backup on CME API failure, never a hardcoded local-hours assumption; Forex closed = fixed Friday 17:00 ET → Sunday 17:00 ET weekly window, no exchange-style cronjob needed. Flagged (not fixed) a known doc gap: UC_4.10.1/UC_4.15.1 still describe Futures reset_time as a fixed literal ("17:00 CST") rather than the dynamic Session_Open_UTC anchor — tracked via QnA_init_docs.md A-18 / CHR-76User instruction (BA session), 2026-11-03 — consolidates UC_6.1.1, UC_4.1.3 BR_4.1.3.5, UC_4.10.1, UC_4.15.1, MT5_Plugin_Business_Logic_v1.md; sourced from RFQ_ Stack Trading Prop Tech V7.pdf §3.3 / §Risk Enforcement Endpoints / §DAILY_LIMIT_BREACH and CR-20260827-001/CHR-76
2026-11-03v1.21CR-22 §22.2 — Forex "market closed" table: Sunday reopen edgeTable stated "Friday 17:00 ET to Sunday 17:00 ET" as one confirmed fixed window, with the Sunday reopen instant presented at the same confidence level as the Friday close instantSplit the two edges by confidence: Friday 17:00 ET close is confirmed (same rollover instant as reset_time, §22.1); Sunday 17:00 ET reopen is flagged ⚠️ as the symmetric/inferred value only — no RFQ/QnA source states the Sunday reopen time explicitly (source only confirms Friday close + generic "24/5 Market Hours", v7_full.txt §SLA Requirement). BA should get explicit client confirmation of the Sunday reopen instantBA self-review during authoring (scope/accuracy check against _SOURCE_MANIFEST.yaml protocol) — no source passage found for the Sunday reopen instant despite exhaustive search of v7_full.txt, QnA STAGE2 series, and all CME/Forex-related CRs
2026-11-05v1.23CR-22 §22.1 — corrected the Anchor values and added explicit DST (EST/EDT) wording§22.1 table stated Futures anchor = 17:00 ET and Forex anchor = 16:00 ET, with no DST breakdownCorrected to: Futures = 18:00 ET (18:00 EST in winter / 18:00 EDT in summer); Forex = 17:00 ET (17:00 EST in winter / 17:00 EDT in summer), Monday–Friday. This is the single authoritative value for reset_time across all UCs — UC docs should cite this section by reference rather than restating a clock value inline.Client-confirmed instruction, 2026-11-05: "Forex: Resets lúc 17:00 ET (17:00 EST vào mùa đông / 17:00 EDT vào mùa hè). Futures: Resets lúc 18:00 ET (18:00 EST vào mùa đông / 18:00 EDT vào mùa hè)." Supersedes v1.22's 17:00 ET (Futures) / 16:00 ET (Forex) values.
2026-11-03v1.22CR-22 §22.1 — Futures reset_time anchor, correction§22.1 stated Futures reset_time = dynamic Session_Open_UTC (sourced from the CME cron), and flagged UC_4.10.1/UC_4.15.1's fixed "17:00 CST" wording as a known doc gap needing future correctionReverted to fixed wall-clock literal. User correction: reset_time is a fixed daily clock (17:00 CST for Futures, confirmed in v7_full.txt §DAILY_LIMIT_BREACH and already correctly stated in UC_4.10.1/UC_4.15.1), not a value derived from CME_Instrument_Details/Session_Open_UTC. That CME-cron-driven mechanism remains correct for §22.2's market-closed determination and for the Dynamic Timekeeper's own T-3min/T-2min/T-30sec/Halt milestones (UC_6.1.1) — it was mistakenly over-applied to reset_time in the prior draft. Removed the "known doc gap" flag against UC_4.10.1/UC_4.15.1 — those UCs needed no correction.User correction (BA session), 2026-11-03 — "mục reset time check lại nhé reset time là lấy theo giờ cố định mà"
2026-11-05v1.24#ops-onboarding channel description"Receives Background Check flags from Checkr and E-Verify failures."Removed the Checkr mention — Rippling's native Flow 6 onboarding now handles the background check entirely, so no Checkr flag is ever emitted to this channel. Channel now only receives E-Verify failures from Rippling's native onboarding.Source: QnA_Level_Promotion.md §4 Round 1, Path A Step 3 Q&A, client-confirmed 2026-09-22 — custom Checkr integration was descoped from Flow 6; this stale mention had not been propagated into the Slack channel description. User instruction, 2026-11-05.
2026-11-09v1.25New CR-23 — Pod Status Lifecycle, Mentee & Pod Leader (Shared)Mentee pod statuses spread across UC_8.2.1, UC_8.2.8, UC_4.14.2, UC_4.17.1; Pod Leader statuses spread across UC_8.2.9 – UC_8.2.13, UC_10.3.2, UC_10.3.3Added CR-23: §23.1 mentee pod_status (null, Assigned, Waitlist, Pending_Pod_Confirmation, Waitlist_Ghost, Inactive_Hold), §23.2 Pod Leader Status (Active, On_Leave, Suspended, Terminated, Permanently_Ineligible) — entered when, blocked from, keeps, moves toBA request 2026-11-09. Includes BA decisions UC_8.2.8 N-05 / N-06 / N-07 (2026-11-09). Terminated → re-invite applies to BPS Terminate only

On this page

CR-01: Numeric Fields1.1 Character Validation — Real-Time Block1.2 Length Limit1.3 Auto-format (no error shown)1.4 Placeholder & RequiredCR-02: Text / Textarea / Search Fields2.1 Whitespace Auto-Trim2.2 Default Length Limits2.3 Placeholder2.4 Required Field & Errors2.5 Search BehaviorCR-03: DropdownCR-04: Filter Dropdown — Default "All"CR-05: Unsaved Data Navigation Warning5.1 Trigger Conditions5.2 Warning Popup ContentCR-06: List PaginationCR-07: File Upload7.1 Upload Limits7.2 Error Messages7.3 Upload Area StatesCR-08: Timestamp Standard — UTC / ISO 8601 / Millisecond Precision8.1 Required Standard8.2 Exception8.3 Affected Fields (Non-Exhaustive)CR-09: Special Field Types9.1 Email Field9.2 Phone Number FieldCR-10: Tooltip InteractionCR-11: Numeric / Monetary Value DisplayCR-12: UTM Attribution Capture — Global, Root Layout12.1 Rationale12.2 Global Root Execution12.3 Persistent Storage — localStorage12.4 Payload InjectionCR-13: Rounding to 2 Decimal PlacesCR-14: WebSocket Reconnection & Snapshot Resiliency (Shared)CR-15: ReferenceCR-15.1: EmailCR-15.2: SlackCR-16: Net PnL Display — Full Precision (Whole Dollars), No AbbreviationCR-17: Soft Breach / Hard Breach — Widget Data Display Behavior (Shared)CR-18: Inbound Webhook — No-Op Returns 200 OK and Drops the Payload (Shared)CR-19: Platform Provisioning & Third-Party Charting Platform Rules (Shared)19.1 Provisioning Sequence — Rithmic-First (The Foundation)19.2 [CHR-117] Sierra Chart — BYOL Disclaimer & Usage-Based Reimbursement19.3 [CHR-129] Quantower — License Validation Endpoint POST /api/license19.4 [CHR-130] MotiveWave + ATAS — B2B License Provisioning19.5 TradeSea — Guide OnlyCR-20: is_default Payment Card Write Scope20.2 Market Data Change Payment Method modal — always writes is_default20.3 Reset / Re-Buy / Time ExtensionCR-21: Admin BPS Operations — General Rules (Shared)21.1 Common payload shape & required fields21.1.1 reason field validation21.1.2 transcript_url field validation & no auto-ticket creation21.2 Admin identity & role source — Auth0 JWT, not database21.4 Ops tooling — no dedicated Admin BPS Console UI in scope21.5 Support Action Audit Trail — immutable BPS_Audit_Log21.6 Action Type ↔ UC_ID mappingCR-22: Reset Time & Market Closed Definition — Futures vs. Forex (Shared)22.1 Reset Time — Definition & Anchor per Asset Class22.2 Market Closed Definition — Futures (CME Cronjob-Driven) vs. Forex (Fixed Weekly Window)CR-23: Pod Status Lifecycle — Mentee & Pod Leader (Shared)23.1 Mentee — pod_status23.2 Pod Leader — Pod_Leader_Registry.StatusGlossaryChangelog