Worker Management, Part 3: Promotions and Salary
Reported by candidates from Ramp's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
Ramp's January 2026 OA drops you into a worker-hours register, and Part 3 is where it stops being a toy. It looks like a pile of string commands. It's really a simulation with per-session history: every office session has to remember which position and pay rate it ran under. Promotions get scheduled, then activate on the next entry at or after the start timestamp. Get that wrong and TOP_N_WORKERS and CALC_SALARY both break. If you blank during the live OA, StealthCoder sits invisibly on your screen as a safety net. Here's the shape of the problem.
The problem
The source assessment is a cumulative four-level worker-hours register for contract workers at a facility. Each level includes every operation from the earlier levels. This page implements Levels 1 through 3 and returns one string result for every query in input order. Level 1: Workers and Office Sessions ["ADD_WORKER", workerId, position, compensation] adds a new worker and stores the worker's position and compensation. If workerId already exists, leave the system unchanged and return false; otherwise return true. Worker IDs and positions contain only English letters and spaces. ["REGISTER", workerId, timestamp] records an office entry when the worker is outside and records an exit when the worker is inside. Calls to REGISTER arrive in increasing timestamp order. Return invalid_request for an unknown worker and registered after a successful entry or exit. ["GET", workerId] returns the worker's total time in the office using completed sessions only. A current session without an exit contributes nothing. Return the empty string when the worker does not exist. Level 2: Ordered Worker Statistics ["TOP_N_WORKERS", n, position] returns at most n workers whose current position equals position. Order workers by completed office time in descending order. Break equal-time ties by worker ID in ascending alphabetical order. Format the result as workerId1(time1), workerId2(time2),.... Return every matching worker when fewer than n exist, and return the empty string when there are no matches. A worker with no completed office session has time 0. Level 3: Promotions and Salary ["PROMOTE", workerId, newPosition, newCompensation, startTimestamp] schedules a new position and compensation. The source guarantees that newPosition differs from the worker's current position and that startTimestamp is greater than the timestamp of the latest REGISTER call for any worker. A scheduled promotion becomes active on the worker's first office entry whose timestamp is at least startTimestamp. A session beginning earlier keeps the previous position and compensation. Return invalid_request when the worker does not exist or already has a promotion waiting to take effect. Return success when the promotion is scheduled. After promotions exist, TOP_N_WORKERS selects workers by current position and ranks them using completed time accumulated in that current position. GET continues to return lifetime completed time across past and current positions. ["CALC_SALARY", workerId, startTimestamp, endTimestamp] returns salary earned between the two timestamps. Only completed office sessions contribute. For each contributing portion of a session, multiply its duration by the compensation attached to that session. Return the empty string for an unknown worker. FastPrep Runner Interface The source uses an array of query rows and one string output per query. FastPrep exposes the same operation rows as workerManagementLevel3(String[][] operations) and returns String[]. Numeric arguments are encoded as base-10 strings. Multipart Series Part 1: Office Registration Part 2: Top Workers Part 3: Promotions and Salary Part 4: Double-Paid Intervals Function workerManagementLevel3(operations: String[][]) → String[] Examples Example 1 operations = [["ADD_WORKER","John","Middle Developer","200"],["REGISTER","John","100"],["REGISTER","John","125"],["PROMOTE","John","Senior Developer","500","200"],["REGISTER","John","150"],["PROMOTE","John","Senior Developer","350","250"],["REGISTER","John","300"],["REGISTER","John","325"],["CALC_SALARY","John","0","500"],["TOP_N_WORKERS","3","Senior Developer"],["REGISTER","John","400"],["GET","John"],["TOP_N_WORKERS","10","Senior Developer"],["TOP_N_WORKERS","10","Middle Developer"],["CALC_SALARY","John","110","350"]] return = ["true","registered","registered","success","registered","invalid_request","registered","registered","35000","John(0)","registered","250","John(75)","","45500"] The session beginning at 150 keeps the old compensation because it starts before 200. The promotion applies when John next enters at 325. Salary over [110,350) is 15*200 + 150*200 + 25*500 = 45500. Constraints 1 <= operations.length <= 500, matching the source's query-count bound. Every row uses an operation available at this level, has the documented arity, and satisfies the source-stated operation preconditions. Every numeric argument is a valid base-10 integer string. Worker IDs and positions contain only English letters and spaces. All REGISTER calls are supplied in increasing timestamp order. Each PROMOTE uses a new position different from the worker's current position. A promotion's startTimestamp is greater than the timestamp of the latest prior REGISTER call for any worker. Each salary query satisfies endTimestamp > startTimestamp >= 0.
Reported by candidates. Source: FastPrep
Pattern and pitfall
The trick is to store sessions, not totals. Keep per worker: current position, current pay, a pending promotion (or none), an open session start, and a list of completed sessions as (start, end, position, pay). On REGISTER entry, check the pending promotion. If entry time is at least startTimestamp, apply it then and clear it, and reset the position-time counter. On exit, append the session. GET sums all sessions. TOP_N_WORKERS sums only sessions under the current position, so track a separate counter that resets on promotion. CALC_SALARY clips each session to [start, end], multiplies the overlap by that session's pay, and ignores the open session. Pitfalls: activating promotions at schedule time instead of next entry, letting a pending promotion block the wrong cases, and breaking ties wrong in the sort. Sort by time descending, then ID ascending. If the logic tangles live, StealthCoder is the hedge.
Drill it cold or hedge it with StealthCoder. Either way, don't walk into the OA hoping you remember the trick.
You can drill Worker Management, Part 3: Promotions and Salary cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. Made for the candidate who got the OA invite this morning and has 72 hours, not six months.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Ramp's OA.
Ramp reuses patterns across OAs. Made for the candidate who got the OA invite this morning and has 72 hours, not six months. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Worker Management, Part 3: Promotions and Salary FAQ
What's the real trick in Worker Management Part 3?+
Store every completed session with its own position and pay rate. Promotions only attach at the next entry at or after startTimestamp, so a session keeps the terms it started with. Salary becomes a clipped overlap times that session's pay. Everything else is bookkeeping around that.
How do I handle a promotion that's pending?+
Keep one pending slot per worker. If PROMOTE arrives and the slot is full or the worker is unknown, return invalid_request. Otherwise fill it and return success. On the next entry with timestamp at least startTimestamp, apply it and clear the slot. An earlier session keeps old terms.
Why does TOP_N_WORKERS differ from GET after a promotion?+
GET returns lifetime completed time across all positions. TOP_N_WORKERS ranks by time accumulated in the current position only. So keep two numbers per worker, or compute the position time from the session list by filtering on the current position and the promotion boundary.
How do I compute CALC_SALARY correctly?+
For each completed session, take overlap = max(0, min(end, endTimestamp) - max(start, startTimestamp)). Multiply by that session's compensation and sum. Skip any open session with no exit. Return the empty string for an unknown worker. Use long to avoid overflow.
How do I prepare for this in 48 hours?+
Build it level by level. Write Level 1 with a map of worker objects, then add sorting for Level 2, then session history for Level 3. Trace the sample by hand, especially the session at 150 that keeps the old pay. Test ties and empty results. The structure matters more than any algorithm.