StackTrading Docs

UC 8.3.1

Flow 8 - Pay Raise Engine (Dual-Rail, Level 7+): recalculates compensation on every promotion to Level 7 or above

FieldValue
BA in ChargeHuyen Dinh
Date Created2026-10-11
Versionv4
Document ReferencesZapier Integration V7.pdf (§Flow 8 — Pay Raise Engine, Dual-Rail, Tables A/B) · RFQ_ Stack Trading Prop Tech V7.pdf (§3.2 Financial & Transaction Endpoints) · client QnA thread (QnA_Level_Promotion.md §5, Round 1–5)

1. Overview

FieldContent
IDUC_8.3.1
Use CaseFlow 8 - Pay Raise (L7+)
DescriptionEvery time a trader is promoted to Level 7 or above, the Middleware recalculates their compensation.[CHR-123] For US W-2 traders, this is a manual-assisted update via a Freshdesk ticket (Rippling has no public API for this). For International contractors, the Middleware calls Dots directly to pay a prorated top-up and update the recurring retainer.
Zapier FlowFlow 8 (Pay Raise Engine, Dual-Rail) — invoked synchronously from Flow 4A (UC_8.1.1), Stage 3 Step 3 (Blocking gate — Flow 6 / Flow 8 redirect), when New_Level > 6
Zapier TableTable A (Forex Level Params —Base_Income, Base_Income_Flex, Title) · Table B (Futures Level Params — same fields)
3rd PartyRippling (US W-2 payroll — manual update only, no API) · Dots (International contractor payouts, one-off top-up + recurring retainer) · Freshdesk (operational ticket for Rippling manual update) · Slack (Ops alert)

Trigger

UC_8.1.1 (Flow 4A), Stage 3 Step 3 (Blocking gate — Flow 6 / Flow 8 redirect) — when a trader's New_Level > 6, the Middleware synchronously invokes Flow 8 and blocks all remaining Stage 3 steps (Reset Balance, Update Risk, Re-Enable Trading) until Flow 8 returns a completed status.

Pre-conditions

  • The trader is being promoted to New_Level > 6
  • Users.compensation_track (Comp_Track) is set — either 'Standard' or 'Flex' — read as-is from the DB, never recalculated.

Post-conditions

  • [If skip condition met] → no action taken.
  • [US W-2, Path A] → [CHR-123] a Freshdesk ticket + Slack alert has been generated for Ops to manually update Rippling. The trader's compensation inside Rippling itself is NOT yet updated (pending manual action) — but the promotion flow itself is complete, and the trader can trade immediately.
  • [International, Path B] → a one-off Dots top-up payout has been dispatched (if applicable) and user_employment_profiles.dots_monthly_retainer has been updated to the new rate.

Basic Flow

Step 1 — Data Lookup & Rate Selection

  1. The Middleware retrieves from Table A (Forex) or Table B (Futures): Base_Income, Base_Income_Flex, and Title.

  2. The Middleware reads Users.compensation_track (Comp_Track) as currently stored in the DB — this field is backend-only and can only be changed manually by HR/Operations inside Rippling; the trader can never change it via the dashboard.

  3. Rate selection:

    • [If Comp_Track == 'Standard'] → New_Pay = Base_Income.
    • [If Comp_Track == 'Flex'] → New_Pay = Base_Income_Flex.
    • International contractors default to Base_Income_Flex.
  4. Skip condition BR_8.3.1.1: [If New_Pay and Title for New_Level are both identical to the trader's current pay and title] → the Middleware bypasses the entire flow. No API call, no Freshdesk ticket, no Dots payout, no Slack alert is generated. s

  5. [Else] → proceed to Step 2 (Path A) or Step 3 (Path B) depending on the trader's employment type (US W-2 vs. International Contractor).

    1. The Middleware queries billing_country directly from the PostgreSQL Users table to decide which path to route the trader into:
    • [If billing_country == 'US'] → Path A (US W-2)
    • [Else] → Path B (International)

Step 2 — Path A (US W-2)

  1. [CHR-123] Since Rippling exposes no public API to update employee compensation, the Middleware fires a webhook to Zapier to generate a Freshdesk ticket and a Slack alert for the Operations team.

    Freshdesk ticket payload:

    FieldValue
    Trader_NameTrader's full name
    User_IDInternal user ID
    Rippling_IDTrader's Rippling employee ID
    New_Job_TitleTitle for New_Level (from Step 1.1)
    New_Compensation_RateNew_Pay (from Step 1.3) — Hourly or Annual, per Base_Income_Type
    • [If only Title changed and New_Pay is unchanged] → the ticket still generates, but New_Compensation_Rate is set to the current (unchanged) rate — Ops only needs to update the job title in Rippling.
  2. Operations uses this ticket to manually update the trader's compensation profile inside the Rippling dashboard, backdating the effective date to Today + 1 Day (calendar-day boundary — see BR_8.3.1.4).

  3. UI behavior: the trading-account processing modal (triggered by Flow 4A) is not blocked by this manual Rippling update. Once the broker account for New_Level is successfully provisioned and the Freshdesk ticket has been successfully created, the modal closes and the trader can trade immediately — regardless of whether Ops has processed the Freshdesk ticket yet.


Step 3 — Path B (International Contractor)

  1. The Middleware calls POST /calculate-prorated-raise .

  2. Data retrieval:

    • Query Users table for compensation_track and Standard_Hours.
    • Query Table A/B for Base_Income, Base_Income_Flex, and Base_Income_Type using New_Level.
  3. Rate selection:

    • International contractors default to Rate = Base_Income_Flex.
  4. Retainer calculation:

    • [If Base_Income_Type == 'Hourly'] → New_Adjusted_Retainer = Rate * ((Standard_Hours * 52) / 12).
    • [If Base_Income_Type == 'Annual'] → New_Adjusted_Retainer = Rate / 12.

    Example (Hourly): Rate = 25 (USD/hour), Standard_Hours = 40 (hours/week) → New_Adjusted_Retainer = 25 * ((40 * 52) / 12) = 25 * (2080 / 12) = 25 * 173.33 = 4,333.33 (USD/month).

    Example (Annual): Rate = 72,000 (USD/year) → New_Adjusted_Retainer = 72,000 / 12 = 6,000 (USD/month).

  5. Proration math:

    • Old value retrieval: the Middleware retrieves Old_Adjusted_Retainer and Old_Comp_Track from the values already saved at the time Flow 4A executed this promotion (the value of the trader's compensation parameters immediately before this raise) — reads user_employment_profiles.dots_monthly_retainer as it stood right before this promotion overwrote it.
    • First-time Level 6→7 case BR_8.3.1.7: no special-case branch is required — see BR_8.3.1.7.
    • Proration_Factor is calculated using Business Days Only (US/Central) — excluding both weekends (Sat/Sun) and US Federal/Bank holidays (e.g. Independence Day, Thanksgiving, Christmas), aligned to the standard US corporate banking/payroll calendar.
    • Prorated_Adjustment = (New_Adjusted_Retainer - Old_Adjusted_Retainer) * Proration_Factor — this is the delta/top-up between old and new rate for the remaining days in the current month, NOT the full remaining-days amount at the new rate.

    Example: Trader is promoted on 2026-11-18 (US/Central). November 2026 has 30 calendar days; counting Business Days Only from 11-19 to 11-30, excluding weekends and the Thanksgiving holiday (11-26, Thu) and the day after if observed as a bank holiday — assume 8 remaining business days out of a 20 business-day month → Proration_Factor = 8 / 20 = 0.4.

    Old_Adjusted_Retainer = 4,000 (snapshot at last promotion), New_Adjusted_Retainer = 4,333.33 (recalculated in Step 3.4 above) → Prorated_Adjustment = (4,333.33 - 4,000) * 0.4 = 333.33 * 0.4 = 133.33 (USD), dispatched immediately as a one-off Dots payout. Starting 2026-12-01, the monthly cron (BR_8.3.1.6) pays the full New_Adjusted_Retainer = 4,333.33.

  6. Automated action:

    • Trigger a one-off Dots API payout for Prorated_Adjustment, dispatched immediately at the moment of promotion (not deferred to the 1st of next month).
    • [CHR-131] Update user_employment_profiles.dots_monthly_retainer = New_Adjusted_Retainer — this value is picked up by the monthly cron job (see BR_8.3.1.6) starting the 1st of next month.
    • Send a Slack alert to Admin: "✅ Pay raise logic triggered for Trader [User_ID]."

2. Business Rules

BR_8.3.1.1: Skip Condition — Identical Pay/Title

If Base_Income (or Base_Income_Flex, per the trader's Comp_Track) and Title for New_Level are mathematically identical to the trader's current pay and title, the entire Flow 8 pipeline is bypassed — no API call, no Freshdesk ticket, no Dots payout, and no operational alert is generated.

BR_8.3.1.4: Effective Date — Calendar Day, Not Rolling 24-Hour

The new pay rate's effective date is Today + 1 Day, based on the calendar day (US/Central), not a rolling 24-hour timestamp. Example: if a trader hits Level 7 at 9:30 PM on 20/9, the raise becomes effective at 00:00 (midnight) US/Central time on 21/9.

BR_8.3.1.6: Path B Recurring Retainer — Internal Cron, Not Dots-Managed Schedule

[CHR-131] Dots does not support a recurring payout schedule at the API level. Instead:

  • user_employment_profiles.dots_monthly_retainer (Decimal, PostgreSQL) stores each International contractor's current monthly rate.
  • An internal cron job runs on the 1st of every month, queries all users with dots_monthly_retainer > 0, and calls POST /v2/transfers individually for each user.

3. Payment Timing Reference

TrackBase Salary Raise (this flow)
US W-2 (Path A)No one-off payment. Rippling applies the new rate natively within its own nextlagging payroll cycle (arrears).
International Contractor (Path B)Monthly Dots retainer paidin advance on the 1st of the month. Prorated_Adjustment top-up dispatched immediately at promotion time (this flow).

Changelog

DateVersionUpdated itemBeforeAfterNotes
2026-10-11v1Initial creationN/AFull SRS for Flow 8 (Pay Raise Engine, Dual-Rail, Level 7+), covering Data Lookup/Rate Selection, Path A (US W-2 Freshdesk degradation), Path B (International Dots cron mechanics), 6 Business RulesSource:QnA_Level_Promotion.md §5 (Round 1–4) + QnA_init_docs.md (B-01→B-09, B-05 excluded as [BLOCKED]). Level 6→7 first-time transition case intentionally omitted pending BA decision.
2026-10-16v2Step 3 (Path B) — Old value retrieval; new BR_8.3.1.7Level 6→7 first-time transition case intentionally omitted pending BA decision (B-05 BLOCKED)Closed B-05: added BR_8.3.1.7 — first-time Level 6→7 reads the same Users.dots_monthly_retainer already written by Flow 6 (UC_8.1.2 Step 11 at the time; renumbered to Step 10 on 2026-10-27 after UC_8.1.2 removed its old Step 6 "Close 1099 Account") as Old_Adjusted_Retainer, no synthetic calculation, no special-case branch.Source: client QnA thread 2026-10-16, resolves QnA_init_docs.md B-05. Applied to QnA_Level_Promotion.md §5 Round 5.
2026-10-20v4Post-condition, Step 3.5/3.6 (Old value retrieval, Retainer update), BR_8.3.1.6Users.dots_monthly_retainer / users.dots_monthly_retaineruser_employment_profiles.dots_monthly_retainer — field moved off the Users table onto its own user_employment_profiles table; column name unchangedBA update per client direction
2026-10-20v3Overview "Zapier Flow" row, Trigger section, Step 1.4 skip-condition wordingDocumented Flow 8's trigger point as "Flow 4A (UC_8.1.1), Stage 5, Path C" — a "Path C" that does not exist in Stage 5; skip condition said "Flow 4A's promotion is considered complete immediately"Corrected trigger point to match UC_8.1.1 v1.3+ (which moved the Flow 6/Flow 8 redirect into Stage 3 Step 3, a blocking gate before Reset Balance/Update Risk/Re-Enable Trading — no "Path C" naming): Overview and Trigger now cite "Stage 3 Step 3 (Blocking gate — Flow 6 / Flow 8 redirect)". Skip-condition wording corrected: skipping Flow 8 only releases Flow 4A's Stage 3 blocking gate immediately — it does not mean the overall promotion (Stage 4-5) is complete.Cross-UC consistency check against UC_8.1.1_v1.md (currently v1.8) while reviewing Flow 8 for related updates — found stale, never updated when UC_8.1.1 v1.3 relocated the redirect from its original Stage 5 position.

On this page