StackTrading Docs

UC 8.1.2

Flow 6 - Level 6 Transition: Country-routed W-2 (Path A) vs. International Contractor (Path B) onboarding, triggered when a trader is promoted to Level 6

FieldValue
BA in ChargeHuyen Dinh
Date Created2026-10-10
Versionv1
Document ReferencesZapier Integration V7.pdf (§Flow 6 — Level 6 Transition, Tables A/B) · RFQ_ Stack Trading Prop Tech V7.pdf (§Financial & Transaction Endpoints, §Immutable Ledger / Proof of Payout)

1. Overview

FieldContent
IDUC_8.1.2
Use CaseFlow 6: Level 6 Transition (W-2 vs. International)
DescriptionWhen a trader is promoted to Level 6 (triggered byUC_8.1.1 Stage 5 Path B), the Middleware routes the trader by billing_country into either a US W-2 employment onboarding (Rippling) or an International Contractor retainer transition (Dots/SignWell).
Zapier FlowFlow 6 (Level 6 Transition) — triggered by Flow 4 Stage 5 Path B (Next_Level == 6)
Zapier TableTable A (Forex Level Params —Base_Income, Base_Income_Flex, Base_Income_Type, Title) · Table B (Futures Level Params — same fields)
3rd PartyRipplingDots Typeform (Offer Configurator forms, embedded on a Stack Trading-hosted page)AWS SESPolygon/Ethers.js via Middleware

Trigger

UC_8.1.1, Stage 5, Path B (Klaviyo promotion branch): Next_Level == 6 — Flow 6 is fired as a mandatory side-effect of Path B, alongside the Promotion_Level_6 Klaviyo event.

Pre-conditions

  • The trader is being promoted to Level 6
  • The trader's billing_country is populated on the PostgreSQL Users table

Post-conditions

  • Path A (US W-2):
    • comp_track ('Standard'/'Flex') and standard_hours are set on the Users record;
    • a Rippling W-2 employment record exists for the trader;
    • the trader has signed their W-2 offer;
    • completed I-9 Section 2 / E-Verify;
    • the trader's payouts are routed to Rippling instead of Dots
  • Path B (International):
    • Requested_Hours (<= 35) has been submitted via the Level_6_Offer_International Typeform and saved to the Users record;
    • the trader's Dots payout profile is confirmed Active;
    • [CHR-131] user_employment_profiles.dots_monthly_retainer is set to Base_Income_Flex;
    • if the promotion occurred mid-month, an immediate one-off Dots transfer for the prorated remainder of the current month has already been triggered (Step 10.4).
  • The post-promotion modal tracked by UC_8.1.1 §UI/UX — Modal A/Modal B closes once every required Flow 6 step for the trader's path is complete.

Basic Flow

Step 1 — Country Check (shared by Path A and Path B)

  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), Step 2 below.
    • [Else] → Path B (International), Step 8 below.

Path A — US W-2

Step 2 — Offer Configurator

  1. The Middleware retrieves Base_Income and Base_Income_Flex for Level 6 from Table A (Forex) or Table B (Futures).

  2. The system dispatches the Level_6_Offer_Configurator email (SES-29) to the trader via AWS SES. This email contains the CTA link to the embedded Typeform below.

  3. This form only asks US traders for Track and Hours — it is a completely separate form from the Path B form; the two forms do not share a validation block.

    Embedded Typeform — "Level 6: Corporate Seat & W-2 Configuration":

    FieldContent
    Form TitleLevel 6: Corporate Seat & W-2 Configuration
    TargetUS W-2 Traders upon reaching Level 6
    Hidden Variables Requireduser_id, base_income, base_income_flex
    Welcome Screen"Congratulations. You have cleared the evaluation tracks, proven your edge, and secured your seat on the desk. Configure your official W-2 Corporate Offer below to formalize your promotion."
    Question 1 (Multiple Choice)"Select your Compensation Track:"Option A: "Standard Track: Hourly Rate of $[base_income] + Comprehensive Corporate Health & Welfare Benefits."Option B: "Flex Track: Hourly Rate of $[base_income_flex] (Maximum Cash Flow, No Benefits)."
    Question 2 (Number)"How many total hours per week do you commit to the desk?"Description/Hint: "This figure is used to generate your official employment schedule and Rippling timesheet."
    Validation Rule (Track A selected)Minimum 30, Maximum 35.Error Copy: "The Standard Track requires a minimum of 30 hours to legally qualify for corporate health benefits." / "Standard Track hours can not exceed 35 per week."
    Validation Rule (Track B selected)Minimum 1, Maximum 29. Error Copy: "Flex Track hours cannot exceed 29 per week. For 30+ hours, you must select the Standard Track." / "The Flex Track requires a minimum of 1 hour."
    RequiredQuestion 1 (Track) and Question 2 (Requested_Hours) are bothrequired — the trader cannot submit the form with either field blank.
    Ending Screen"Offer configuration locked. Our HR system will email your official Rippling onboarding package and employment agreements shortly. Welcome to the team."
  4. On submit, the Middleware updates the Users record: comp_track = 'Standard' (Track A) or 'Flex' (Track B), and standard_hours = Requested_Hours

  5. [If Track A] → once the trader is hired in Rippling (Step 3 below), Rippling's native platform automatically emails the trader the portal link to complete health and welfare benefits enrollment — the Middleware does not build this enrollment UI or call any separate API for it.

Step 3 — Zero-Entry Onboarding

  1. The Middleware calls Rippling's /events/hr/v1/worker.hire. Rippling itself detects an existing profile via email and Check: IF Employee_Exists → Rehire. ELSE → Create New" framing.

  2. The worker.hire payload includes:

    FieldValue
    RateBase_Income (if Track A) or Base_Income_Flex (if Track B)
    Work_ScheduleDaily breakdown of hours per weekday. Since markets are open Monday through Friday, the Middleware dividesRequested_Hours evenly across those five days: hours_per_day = Requested_Hours / 5. Example: a trader entering 20 hours/week is sent to Rippling as 4 hours/day, Monday through Friday.
    TitleFrom Table A/B for Level 6
  3. Once worker.hire succeeds, Rippling automatically emails the trader their onboarding invitation and login credentials — this is fully automated on Rippling's side.

Step 4 — Offer Generation

  1. The Middleware triggers Rippling's native W2_Offer_Template (built entirely inside Rippling, not by SotaTek)

  2. Dynamic fields on the offer, read from Table A/B for Level 6:

    ConditionField set
    Base_Income_Type == 'Hourly'Hourly_Rate = Base_Income (Track A) or Base_Income_Flex (Track B) — pulled directly from Table A/B
    Base_Income_Type == 'Annual'Base_Salary = the annualized Base_Income/Base_Income_Flex value sent as-is — no hourly-rate calculation is performed
    (always)Max_Authorized_Hours = 35 (Track A) or 29 (Track B); Job_Title from Table A/B
  3. The Middleware sends the W2 Offer via Rippling with an "Identity Confirmation" checkbox — this form and the identity confirmation are hosted and executed entirely inside Rippling.

Step 5 — Immutable Ledger Logging

  1. Once the W2 Offer is signed, the Middleware calls POST /api/ledger/record with trader_id, metric_category = "W2 Offer Executed", metric_value = "Level 6 W2 Trader Status Achieved", date = Today, receipt_hash = [Rippling Envelope ID].
  2. This uses the exact same two-step receipt_hash → on-chain tx_hash mechanism in UC_8.1.1 §Stage 1 step 6, and the Middleware independently writes the metric on-chain via Ethers.js/Polygon and stores the real tx_hash.

Step 6 — Hours Declaration

  1. Rippling's native Workflow Automator feature — which triggers internal tasks and emails based on HR events — fires the "Trading Hours Declaration" form. This is a native Rippling compliance form built by the client's own team; SotaTek does not build this form.

Step 7 — Compliance Hand-Off

  1. Rippling handles I-9 Section 2 and E-Verify automatically. If E-Verify fails, Rippling alerts Ops.

Path B — International

Step 8 — Country-Routed Form (Hours Only)

  1. The system dispatches the Level_6_Offer_International email (SES-30) to the trader via AWS SES. This email contains the CTA link to the embedded Typeform below. The form asks only for Requested_Hours (no Track selection, since international contractors are not eligible for US health benefits)

    Embedded Typeform — "Level 6: Global Retainer Configuration":

    FieldContent
    Form TitleLevel 6: Global Retainer Configuration
    TargetInternational Contractors upon reaching Level 6
    Hidden Variables Requireduser_id, base_income_flex
    Welcome Screen"Congratulations. You have cleared the evaluation tracks and proven your edge. As a Level 6 International Partner, you have unlocked institutional profit splits and a baseline retainer. Let's configure your payout profile."
    Question 1 (Statement)"Your Base Income Structure: As a senior international contractor, your base income is calculated via the Flex Track. Your initial hourly rate is set at $[base_income_flex] USD. You will continue to receive your performance bonuses on top of this retainer."
    Question 2 (Number)"How many total hours per week do you commit to the desk?"Description/Hint: "We use this metric to prorate your monthly retainer payout via Dots."
    Validation RuleMinimum 1, Maximum 35. Error Copy: "Flex Track hours can not exceed 35 per week." / "The Flex Track requires a minimum of 1 hour."
    RequiredQuestion 2 (Requested_Hours) isrequired — the trader cannot submit the form with it blank 
    Ending Screen"Parameters locked. Our Operations team is updating your payout profile to reflect your new retainer. Welcome to the senior desk."
  2. The flow halts until the form is submitted and Requested_Hours is saved to the SQL database.

Step 9 — Dots Payout Validation

  1. The Middleware calls the Dots API to verify the contractor's payout profile status.

    • [If Active] → proceed to Step 10.

Step 10 — International Contractor Notification

  1. Once Dots returns Active, the system fires the Level_6_International_Contractor email (SES-13) via AWS SES, providing the trader their operational instructions.
  2. Update International Base = Base_Income_Flex (the International track always uses the Flex-track income figure, regardless of hours).
  3. [CHR-131] There is no Rippling action for Path B — international traders remain contractors. The Middleware calculates the monthly retainer amount based on the trader's Base_Income_Type and Requested_Hours from the submitted form, and updates the recurring Dots monthly retainer trigger:
    • Formula (Hourly): If Base_Income_Type == 'Hourly': dots_monthly_retainer = Base_Income_Flex * ((Requested_Hours * 52) / 12)
    • Formula (Annual): If Base_Income_Type == 'Annual': dots_monthly_retainer = Base_Income_Flex / 12
    • It writes/updates the calculated value to user_employment_profiles.dots_monthly_retainer (Decimal).
    • An internal cron job runs on the 1st day of every month:
      • Queries all users with dots_monthly_retainer > 0.
      • For each matching user, calls POST /v2/transfers via the Dots API.
  4. Mid-month promotion — immediate prorated payout. Because the Step 10.3 monthly cron only runs on the 1st of the month in advance, a Level 6 promotion that lands mid-month requires an additional one-off payout for the remainder of the current month, on top of saving dots_monthly_retainer for future cron runs:
    • Adjusted_Retainer is the same full monthly retainer value just calculated in Step 10.3 (Base_Income_Flex * ((Requested_Hours * 52) / 12) for Hourly, or Base_Income_Flex / 12 for Annual).

    • Proration_Factor: Business Days Only (US/Central) — remaining business days in the current month (from the promotion date to month-end) divided by the total business days in the current month, excluding both weekends (Sat/Sun) and US Federal/Bank holidays.

    • The Middleware calculates the prorated amount for the remaining US business days of the current month: Prorated_Amount = Adjusted_Retainer * Proration_Factor.

      Example: Trader is promoted to Level 6 on 2026-11-18 (Wednesday, US/Central), Base_Income_Type = 'Hourly', Base_Income_Flex = 25 (USD/hour), Requested_Hours = 40 → Adjusted_Retainer = 25 * ((40 * 52) / 12) = 4,333.33 (USD/month).

      Total business days in November 2026: the month has 30 calendar days, 8 of which fall on a weekend (Sat/Sun: 11-07/08, 11-14/15, 11-21/22, 11-28/29) → 22 weekdays. Thanksgiving (Thu 11-26) is a US Federal holiday and is also excluded → 21 total business days in the month.

      Remaining business days (11-19 through 11-30): 11-19 (Thu), 11-20 (Fri), 11-23 (Mon), 11-24 (Tue), 11-25 (Wed), 11-27 (Fri), 11-30 (Mon) → 7 remaining business days (11-21/22 and 11-28/29 are weekends, 11-26 is Thanksgiving, all already excluded from the count).

      Proration_Factor = 7 / 21 = 0.3333. Prorated_Amount = 4,333.33 * 0.3333 = 1,444.44 (USD), dispatched immediately as a one-off Dots payout. Starting 2026-12-01, the monthly cron pays the full Adjusted_Retainer = 4,333.33.

    • It immediately triggers a one-off Dots transfer for Prorated_Amount via POST /v2/transfers — it does not wait for the next 1st-of-month cron run.

    • (For comparison, Path A/Rippling needs no equivalent step: the Middleware only passes the selected rate and Requested_Hours to the Offer Generation step in Step 4, and Rippling's native in-arrears W-2 payroll handles the partial month itself.)

Step 11 — Sync

  1. The Middleware synchronizes the Start Date (the effective date of the Level 6 promotion) and Title (fetched from Table A/B for Level 6) into the Users table and the Independent Contractor Agreement. This ensures International contractors have the exact same official job title and effective start date as their W-2 counterparts.

Business Rules

BR_8.1.2.1: Post-Signature Lock

  • Track A (Full Benefits): Requested_Hours must be entered as a value between 30 and 35 inclusive. 30 is a legal minimum required to qualify for the corporate health benefits package — the trader cannot enter a value lower than 30 (Source: QnA_Level_Promotion.md Section 4.3, Round 4, Q2.2/A2.2).
  • Track B (Flex Cash): Requested_Hours must be between 1 and 29 inclusive.
  • Path B (International): Requested_Hours must be between 1 and 35 inclusive.
  • Lock after signature: once the Offer Configurator form is submitted and the Rippling W-2 contract is generated and signed, the trader's default schedule (standard_hours) is locked — it cannot be changed dynamically through the dashboard. Any later change requires opening an internal HR support ticket, handled manually by Operations — this is a Day 2 item, not built in the current scope.

BR_8.1.2.3: Base_Income_Type Lock

base_income_type is not user-editable. It is hardcoded by level in Table A/B: 'Hourly' for Levels 6 through 9, automatically switching to 'Annual' once the trader is promoted to Level 10 (Senior Trader 1).

BR_8.1.2.4: Track Switching Ban

Once the W-2 contract (Path A) is signed, the trader cannot switch between the Standard and Flex compensation tracks via the dashboard — no track-switching UI is built. Any future track change is a manual Operations action performed directly inside Rippling.

BR_8.1.2.5: 3rd-Party API Failure Handling (SEV-01 Halt)

Any call this flow makes to a 3rd-party API (Rippling, Dots, or any other external vendor integrated by Flow 6) that fails triggers a SEV-01 Slack alert and an immediate HALT of the flow in #ops-general (C0BR8LRC5MK / Test C0BR6UXRR8D).

Slack Error Message Format:

  • Message Content:
    [SEV-01] Level 6 Promotion API Failed
    Trader ID: [user_id]
    Email: [trader_email]
    Failed Action: [API endpoint or integration name, e.g., worker.hire on Rippling]
    Error Detail: [HTTP Status Code - Error Message]
    Status: The automated Level 6 transition flow has been HALTED. Manual intervention is required to complete the promotion.

BR_8.1.2.6: Rebuy/Termination Impact on Comp Data

If a Level 6+ W-2 trader is terminated (Hard Breach) and subsequently purchases a Rebuy, the Middleware must clear comp_track and standard_hours on the Users record. The trader returns to the Associate Track (no salary or benefits). If the trader reaches Level 6 again, this entire UC_8.1.2 flow runs again from Step 1, including a fresh worker.hire call — Rippling resolves rehire-vs-create-new itself via email/SSN matching, same as the first time.

Changelog

DateVersionUpdated itemBeforeAfterNotes
2026-10-10v1Initial document—Full SRS for Flow 6 authoredSource: QnA_init_docs.md (37/38 confirmed, A-10/SES-13 pending), QnA_Level_Promotion.md Section 4/4.1/4.2/4.3/7
2026-10-11v1Step 6, Step 7.1, Step 8.2, Post-condition Path AStep 6 was "Suspend Dots Payout Trigger" (clears Users.dots_monthly_retainer), Step 8.2 derived "Close 1099→Create W-2" from Step 6+Step 3, Step 7.1 described Rippling Workflow Automator as a passive HR-event triggerStep 6 renamed to "Close 1099 Account" (bookkeeping-only flag, does not touch dots_monthly_retainer — that field is never set for Path A traders); Step 8.2 clarified both sides complete independently (W-2 created in Step 3, 1099 closed in Step 6); Step 7.1 clarified Middleware actively calls Rippling API to trigger Workflow Automator, passing Typeform values; added [BLOCKER] notes at Step 5.3/6.2 on the disabled Rippling "Call a public API" actionSource: QnA_STAGE6_CAREER_PATH.md STAGE6-025, STAGE6-027, STAGE6-028
2026-10-20v1Post-condition Path B, Step 6, Step 11.3, Changelog 2026-10-11 row (reference text)Users.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-26v1Step 10 — removed Suspended/failed branchStep 10 cited UC_5.4 BR_5.4.8/BR_5.4.9 (Dots suspension webhook listener → payout_status = 'Suspended' → Dots_Profile_Action_Needed email) for the non-Active caseBranch removed — Step 10 now only covers the Active case (proceed to Step 11). The cited BRs no longer exist: CHR-80 (2026-10-21/23) removed the entire Dots suspension webhook listener + payout_status gate from both UC_5.4 (§7 Sub-flow B, BR_5.4.8/BR_5.4.9) and UC_5.8 (P7 pre-condition)Broken link fix — CHR-80 removed the underlying mechanism this step relied on; no replacement rule defined upstream, so the branch is dropped rather than re-authored without a source
2026-10-27v1Post-condition Path A/B; Step 6 "Close 1099 Account" removed entirely (all later Path A/B steps renumbered down by one: old 7→6, 8→7, 9→8, 10→9, 11→10, old 12 "Agreement Storage" removed, old 13 "Sync"→11); Step 10 (new) gained sub-step 10.4Step 12 "Agreement Storage" (old numbering) had the Middleware store the signed ICA to S3 and save contractor_agreement_s3_uri on Users as part of Flow 6 Path B; Step 11.3 (old numbering) only described the 1st-of-month recurring cron, with no mid-month proration logic; Step 6 said the Middleware "flags the trader's contractor status as inactive/archived on the Users record" (a bookkeeping write)"Agreement Storage" step removed entirely — the ICA signed via SignWell at Stage 3 KYC (Flow 3E) already covers Levels 1-24, so Flow 6 does not re-sign or re-store it; S3 storage happens at Flow 3E, triggered by SignWell's document-signed webhook, not here. Step 6 "Close 1099 Account" removed entirely (not just corrected to a no-op) — there is no DB write, no Dots API call, and no "1099 status" field at all for this step; dots_payee_id/payout_status are left untouched, and the payout-routing switch from Dots to Rippling happens passively inside Flow 5 (Payouts) every pay cycle, based on billing_country/current_level. All subsequent Path A/B steps renumbered down by one to close the gap. "Sync" step gained sub-step on mid-month proration: a Level 6 promotion landing mid-month must calculate the prorated remainder of the current month (Adjusted_Retainer * Proration_Factor) and trigger an immediate one-off POST /v2/transfers, in addition to saving dots_monthly_retainer for future cron runsSource: QnA_Level_Promotion.md Section 4.4, Round 5 (Q1/A1 closes STAGE6-OQ-03; Q2/A2 closes STAGE6-OQ-04, overrides Round 3 Section 4.2 Q1/A1; Q4/A4 clarifies STAGE6-028)
2026-10-27v1Step 10.4 — formula spelled outAdjusted_Retainer * Proration_Factor was stated with no definition of either term, no worked example, and no Proration_Factor methodology — left ambiguous how to actually compute the mid-month prorated payoutClarified: Adjusted_Retainer = the same full monthly retainer just computed in Step 10.3 (no "Old" value to subtract, unlike the Level 7+ raise delta formula in UC_8.3.1 BR_8.3.1.6, since this is the trader's first-ever Dots retainer); Proration_Factor = remaining Business-Days-Only (US/Central, excluding weekends and US Federal/Bank holidays) divided by total business days in the current month, same methodology as UC_8.3.1 Step 3.5; added a fully worked numeric example mirroring the one already confirmed in UC_8.3.1Root source (QnA_Level_Promotion.md Round 5 Q1/A1) only gave the bare formula without defining terms; cross-referenced UC_8.3.1's already-confirmed Proration_Factor methodology (same underlying business-days convention) to fill the gap rather than inventing a new one

On this page