QnA Init Docs — UC_8.3.1 (Flow 8 - Pay Raise, L7+)
UC liên quan: UC_8.3.1 — Flow 8: Pay Raise Engine (Dual-Rail)
Trigger: Promotion Level 7+ (W-2 or Senior Contractor) — xem thêm mục [CROSS_UC_DEPENDENCY] bên dưới
Agent tạo: Agent 2 (Challenger), theo system_init_workflow.md — Init Flow
Ngày tạo: 2026-10-10
Nguồn: References/QnA from clients/07_STAGE6_CAREER_PATH/level promotion/QnA_Level_Promotion.md → Section 5 (business logic gốc + Round 1-4)
| ID | Câu hỏi | Giả định (BA/QC đề xuất) | BA chốt (ưu tiên cao nhất) | Trạng thái |
|---|
| B-01 | UC_8.1.1 (Flow 4A) đã chốt tại mục A-19 (QnA_init_docs.md của UC_8.1.1, nguồn STAGE6-008): "Path C, với New_Level > 6 (vd Level 7,8,9) → MUST trigger Flow 8 (Pay Raise Engine) để recalculate compensation". Vậy lệnh gọi Flow 8 từ Flow 4A là đồng bộ (middleware chờ Flow 8 xử lý xong trước khi coi promotion hoàn tất) hay bất đồng bộ (fire-and-forget, promotion vẫn hoàn tất ngay dù Flow 8 chạy nền)? | Đề xuất: bất đồng bộ — Flow 8 chỉ ảnh hưởng compensation/payroll, không ảnh hưởng trading account/ledger (đã xử lý xong ở Stage 1-4 của Flow 4A). Promotion UI (certificate, celebration modal) không cần chờ Flow 8. Nếu Flow 8 fail, không rollback promotion. | Không — Flow 8 phải done thì Flow 4A mới được coi là done promotion flow (đồng bộ, không phải fire-and-forget). | ✅ Đã chốt |
| B-02 | Flow 8 trigger ởmọi level >6 (7, 8, 9, ...24) mỗi lần promote, hay chỉ trigger khi bước qua mốc W-2/Senior Contractor (vd chỉ Level 7 lần đầu, các level sau 7 không đổi track)? Business logic gốc ghi "Trigger: Promotion Level 7+" — có thể hiểu là >= 7 (mọi lần) hoặc đúng lúc chạm 7 (một lần). | Đề xuất: >= 7, mọi lần promote (khớp với Data Lookup "Retrieve ... for the New Level" — ngụ ý chạy lại mỗi lần vì mỗi level cóBase_Income khác nhau trong Table A/B). Round 2 Q1/A1 (skip-if-identical) cũng ngụ ý flow CHẠY mỗi lần, chỉ bypass action nếu lương không đổi — nếu chỉ trigger 1 lần duy nhất thì rule skip-if-identical sẽ vô nghĩa. | If the Base_Income (or Base_Income_Flex) and the Title for the new level are mathematically identical to the trader's current level, you must completely bypass this flow. Skip-rule vẫn áp dụng. Xác nhận trigger ở mọi level >= 7 mỗi lần promote. | ✅ Đã chốt |
| ID | Câu hỏi | Giả định (BA/QC đề xuất) | BA chốt (ưu tiên cao nhất) | Trạng thái |
|---|
| B-03 | Comp_Track là field backend-only, chỉ HR/Ops sửa tay trong Rippling (đã chốt QnA Round 1 Q3/A3). Nhưng giá trị khởi tạo ban đầu (lúc trader mới hire ở Level 6, trước khi chạm Level 7 lần đầu) được set bởi ai/khi nào — có thuộc scope Flow 6 (Level 6 Transition) không? | Đề xuất: thuộc scope Flow 6 (UC_8.1 — "Flow 6 - L6 Transition", hiện "[Not yet authored]") — Typeform Offer Configurator (Path A/B riêng biệt theo QnA Flow 6 Round 2) là nơi setcomp_track lần đầu. UC_8.3.1 chỉ đọc field này, không set. | đồng ý assumption | ✅ Đã chốt |
| B-04 | Round 1 A4 yêu cầu backend tínhOld_Adjusted_Retainer để làm input công thức delta (New_Adjusted_Retainer - Old_Adjusted_Retainer) * Proration_Factor, nhưng chưa có nguồn nào xác nhận: Old_Adjusted_Retainer được tính lại từ Table A/B tại thời điểm promote (dùng current_level cũ + Rate cũ) hay đọc từ 1 field đã lưu sẵn trong DB (vd cột mới users.current_adjusted_retainer được cập nhật mỗi lần raise)? | Đề xuất: tính lại real-time tại thời điểm promote — query Table A/B bằngcurrent_level (level TRƯỚC khi promote, lấy từ Users.current_level trước khi field này được update sang New_Level) + compensation_track hiện tại, áp cùng công thức Adjusted_Retainer (Hourly/Annual) để ra Old_Adjusted_Retainer. Không cần thêm cột mới nếu order of operations đảm bảo đọc current_level TRƯỚC khi Flow 4A ghi đè. | Không — lấy theo con số đã lưu lúc Flow 4A chạy (snapshot tại thời điểm lên level), KHÔNG tính lại real-time theo trạng thái hiện tại. Đây phải là bộ param "inject" tại đúng thời điểm lên level đó, không phải truy vấn lại hiện tại. Comp_Track cũng lấy theo field đã lưu trong DB (không tính lại). | ✅ Đã chốt — 🔴 HIGH (ảnh hưởng trực tiếp công thức breaking-change đã chốt ở Round 1) |
| B-05 | [EN] For the very first time a trader hits Level 7 (i.e. they are moving from Level 6 → Level 7, right after Flow 6 "Level 6 Transition" has run) — at Level 6, the trader's pay is tracked using Flow 6's own fields (Base_Income / Base_Income_Type), not the "Adjusted_Retainer" concept, which only exists inside Flow 8's logic. Now, following B-04's answer (Old value = the number already saved at the time Flow 4A ran, NOT recalculated live), Flow 8 Path B still needs an Old_Adjusted_Retainer number to subtract in the delta formula (New_Adjusted_Retainer - Old_Adjusted_Retainer) * Proration_Factor. But for this very first Level 6→7 transition, there is no prior "Adjusted_Retainer" value ever saved for this trader — Flow 8 has never run for them before. Question: should the system take the trader's Level 6 pay data (Base_Income + Base_Income_Type from Flow 6) and run it through the SAME Adjusted_Retainer formula (Hourly → annualize via Standard_Hours, or Annual → divide by 12) to produce a synthetic Old_Adjusted_Retainer for this one-time case? Or is the Level 6→7 transition a special exception — for example, no subtraction at all, and the trader is paid the FULL New_Adjusted_Retainer * Proration_Factor for the remaining days (since Level 6 was never paid under the Dots-retainer mechanism in the first place)? | Đề xuất: áp dụng cùng công thức Adjusted_Retainer cho dữ liệu Level 6 (Base_Income_Type Hourly/Annual theo Flow 6) để raOld_Adjusted_Retainer — không coi là ngoại lệ, vì Flow 6 Round 2 đã xác nhận trader International nhận lương qua Dots monthly retainer kể cả ở Level 6. | No synthetic calculation. Level 6 is already paid under the Dots-retainer mechanism for International contractors — Flow 6 (Path B) already calculates and saves the initial monthly retainer to users.dots_monthly_retainer at the Level 6 transition. For the Level 6→7 promotion, the Middleware simply queries the existing Users.dots_monthly_retainer field to serve as Old_Adjusted_Retainer — exactly the same mechanism used for Level 8, Level 9, and every subsequent promotion. No special-case branch required. | ✅ Đã chốt |
| ID | Câu hỏi | Giả định (BA/QC đề xuất) | BA chốt (ưu tiên cao nhất) | Trạng thái |
|---|
| B-06 | Round 2 Q2/A2 xác nhận Path A đổi sang Freshdesk ticket + Slack alert khi Rippling không có API. Nếuwebhook Zapier tạo Freshdesk ticket thất bại (Zapier timeout, Freshdesk API lỗi) — có retry/alert riêng không, hay chỉ dựa vào Slack alert làm backup thông báo? | Đề xuất: theo pattern Discord bot failure handling đã dùng ở UC_8.1.1 (A-14) — 5xx/429 retry qua cron 30 phút, 404/4xx drop + Slack alert#ops-general với message rõ Trader [ID] + lý do fail, để Ops không bị mất thông tin backdate. | đồng ý | ✅ Đã chốt — 🔴 HIGH |
| B-07 | Skip-rule (Round 2 Q1/A1) áp dụng khiBase_Income/Base_Income_Flex và Title giống nhau. Nếu chỉ Title đổi (vd đổi chức danh ở level mới) nhưng lương giữ nguyên — Flow 8 có cần chạy để chỉ update Title (qua Freshdesk ticket Path A, hoặc gọi /calculate-prorated-raise Path B chỉ để đổi field hiển thị, không có Prorated_Adjustment) không? | Đề xuất: vẫn chạy flow nhưng chỉ phần Title update (ticket payload chỉ cóNew_Job_Title, bỏ New_Compensation_Rate hoặc để = giá trị cũ); Path B không cần gọi /calculate-prorated-raise nếu Base_Income_Flex/Base_Income không đổi — chỉ cần 1 lệnh update Title riêng (có thể qua endpoint khác hoặc field Title trong Users table, chưa rõ cơ chế update Title cho Path B). | đồng ý assumption | ✅ Đã chốt |
| ID | Câu hỏi | Giả định (BA/QC đề xuất) | BA chốt (ưu tiên cao nhất) | Trạng thái |
|---|
| B-08 | Round 3 Q4/A4 chốt thêm cộtusers.dots_monthly_retainer + cron ngày 1 hàng tháng gọi POST /v2/transfers cho user có dots_monthly_retainer > 0. Nếu POST /v2/transfers fail cho 1 user cụ thể (vd Dots API lỗi tạm thời) — cron có tiếp tục xử lý user tiếp theo (fail-isolated per-user) hay dừng toàn bộ batch? | Đề xuất: fail-isolated per-user — mỗi user là 1 transfer riêng, lỗi 1 user không block user khác; user lỗi được log + alert Slack#ops-general, retry ở lần cron kế tiếp (ngày 1 tháng sau) KHÔNG tự động retry trong tháng (tránh double-pay nếu request đầu thực ra đã thành công nhưng response timeout). | đồng ý | ✅ Đã chốt |
| B-09 | Khi Prorated_Adjustment one-off payout (dispatch ngay lúc promote theo Round 4 Q2/A2)và cron tháng sau cùng update dots_monthly_retainer = Adjusted_Retainer — có khả năng race condition nếu promotion xảy ra đúng ngày 1 lúc cron đang chạy (vd promote lúc 00:05 ngày 1, cron chạy lúc 00:00 ngày 1 dùng giá trị dots_monthly_retainer CŨ)? | Đề xuất: không coi là race condition nghiêm trọng — Prorated_Adjustment chỉ tính cho "remaining days trong tháng hiện tại", nếu promote đúng ngày 1 thì remaining days = toàn bộ tháng, về bản chất giống hệt việc cron đã dùng rate mới luôn (không có ngày nào bị trả rate cũ). Không cần xử lý đặc biệt. | Không cần cover case này — chốt theo đề xuất BA/QC, bỏ qua race condition này. | ✅ Đã chốt |
| ID | Nội dung |
|---|
| B-P-01 | Pattern "graceful degradation khi vendor thiếu API" (Rippling không có API update compensation → Freshdesk ticket + Slack alert cho Ops) đã xuất hiện ở Flow 8 Path A. Nếu pattern này lặp lại ở flow khác (vd vendor khác cũng thiếu API) → đề xuất tách thành CR riêng mô tả chuẩn payload Freshdesk ticket (Trader Name/User ID/vendor ID/thay đổi cần làm). Chưa đủ dữ liệu để confirm lặp lại — chỉ ghi nhận candidate. |
- Đã chốt (từ QnA có sẵn, không cần hỏi lại BA): toàn bộ business logic gốc + Round 1-4 của Flow 8 (effective date, comp_track field, track không editable, skip-if-identical, Path A Freshdesk degradation, Path B cron mechanics, Dots timing, phân biệt Flow 5 vs Flow 8) — xem
QnA_Level_Promotion.md Section 5.
- Đã chốt bởi BA (lần này): B-01 (Flow 8 phải đồng bộ với Flow 4A — Flow 4A chỉ done khi Flow 8 done), B-02 (trigger ở mọi level >= 7 mỗi lần promote), B-03 (comp_track khởi tạo lần đầu thuộc scope Flow 6), B-04 (Old_Adjusted_Retainer/Comp_Track lấy theo giá trị đã snapshot/lưu lúc Flow 4A chạy tại thời điểm lên level, KHÔNG tính lại real-time — 🔴 breaking impact tới công thức Round 1), B-05 (Level 6→7 lần đầu KHÔNG cần synthetic calculation — đọc trực tiếp
Users.dots_monthly_retainer đã được Flow 6 ghi sẵn, dùng chung mechanism với mọi promotion N→N+1 khác), B-06 (Freshdesk ticket failure theo pattern Discord bot: 5xx/429 retry cron 30 phút, 404/4xx drop + Slack alert), B-07 (Title-only change vẫn chạy flow, chỉ update Title), B-08 (cron Dots fail-isolated per-user, retry ở cron tháng sau), B-09 (bỏ qua race condition ngày 1).
- Pattern candidate: B-P-01.
- ✅ ĐỦ ĐIỀU KIỆN qua Step 3 (Architect) theo PAUSE Gate của
system_init_workflow.md — toàn bộ B-01→B-09 đã chốt, không còn case nào bị loại trừ.