Skip to main content

Solution: select at each job's last safe moment, not at a clock time

This page states the change to auto-select, the reasoning behind it, and the replay evidence for it. It is the third page of the auto-select timing initiative. The problems page defines the terms and shows why the current 09:00 and 17:00 runs miss 703 jobs in twelve weeks. All replays below use those 703 misses at outlets with the flag on, shifts starting 22 June to 13 September 2026.

1. The user stories the solution serves​

  • As ops, I want every job that has an eligible applicant to get a selection before it expires, so that jobs stop expiring with applicants waiting.
  • As a hiring manager on a job posted a day or more ahead, I want to keep the deadline I know, the day-before run, so that the system never picks before my usual chance.
  • As a hiring manager on a short-notice job, I want the system to pick only when I have not, and only with enough time left for the jodder, so that I am not overridden while I am still choosing.
  • As a jodder, I want at least 6 hours between selection and the shift, so that I can acknowledge and prepare.
  • As an engineer, I want every automatic selection attempt logged with its outcome, so that the change can be measured after it ships.

2. The solution in five rules​

#rulewhat changes in the code
1Select at the last safe moment. When a job reaches 8 hours before its shift (normal job) or 6 hours before its shift (short-notice job) and is still open with a live eligible applicant at an outlet with the flag on, select the top applicant. Expire the job only if selection fails or nothing is eligible.One branch in command:clear_jobs_expire, which already visits every open job at 8 hours before the shift, every 10 minutes. It calls the same AutoSelectApplicantService::processAutoSelect the two existing commands call. For short-notice jobs the visit moves from the shift start to 6 hours before it.
2Keep the day-before run. The 09:00 and 17:00 runs stay as they are.Nothing. They give more notice to the jobs they catch. The short-notice run that shipped on 16 September becomes redundant once rule 1 is live and can be retired.
3After a dropout, re-select at once. When a selected jodder cancels or is removed, carry the parent job's other applicants to the new open job and select the top one immediately. Re-advertise only if none of them is free.The repost command copies the parent's job_user rows with status: 1 (applied) to the clone, minus any jodder who now holds an overlapping shift, and calls selection once. Later, re-open the same row instead of cloning.
4Log every attempt. Job id, trigger (day-before run, last safe moment, dropout), time, outcome, applicant, failure reason.A log line and a table write where processBatch's result is thrown away today.
5Fix the pick. A missing rank sorts last. If the top applicant fails, try the next. Retry a failed UKG call once and log the reason. Run the same credit-floor check a manual selection runs. Stop the repost command copying auto_select_user_id.AutoSelectApplicantService::determineTopApplicant, processAutoSelect, JodJobAutoJobPostingCommand.

The preparation floor is a setting: 6 hours by default. The decisions table on the index page holds the open choices on the floor, on night-time selections, and on the four outlets that switched the flag off.

3. The proposed timing, on the same three jobs the current runs miss​

Legend: the milestones labelled "the system selects" are the new automatic selections. Job A keeps its day-before run and gains a second attempt at its expiry moment, 8 hours before the shift. Job B gets its one attempt 6 hours before the shift, which is at night here; the index page holds the choice between night selections and pulling them to 21:59 the evening before. Job C is selected the minute the dropout happens, from the applicants the parent job already had.

4. Why this and not a better clock time​

No clock time works, because the right moment is different for every job. The replay searched every pair of whole hours. The best pair, 01:00 and 06:00, would have caught 388 of the 703 misses (55%). The best pair inside waking hours, 06:00 and 23:00, 357 (51%). Today's pair, 184 (26%). The winning hours were not office hours. They were the hours that sit just after the evening applicants and just before the expiry of the common morning and afternoon shifts. That is a function of each shift's start time, so a fixed pair only approximates "8 hours before the shift". The expiry command already computes that moment for every job.

A clock-time sweep takes the manager's choice; the expiry moment does not. Any schedule that runs whenever an applicant exists would have picked before the manager on about half of the jobs managers select themselves, because managers on normal jobs take a median 15.5 hours after the first applicant. The expiry moment cannot pre-empt a manager on a normal job, because nobody can select after expiry today either. On short-notice jobs it takes 9.5% of manager picks, and those managers were picking with a median 4 hours left before the shift, less notice than the rule gives.

The floor is set by ACK1. A jodder can acknowledge only until 3 hours before the shift. 6 hours leaves a margin. 4 hours is the tightest sensible setting. 3 hours is the edge.

The day-before run stays because it gives more notice. A job it catches is filled 15 to 27 hours ahead. The expiry moment is the backstop for everything it misses, not a replacement.

Re-selecting after a dropout beats cloning an empty job. 56% of the parent job's other applicants find the clone and apply again by themselves, and then nobody selects them. Selecting them at the moment of the dropout removes the wait, keeps the 44% who never come back, and the people it selects complete at 86%, against 42% for clones as a whole.

5. The replay proof​

Catch on the 703 misses. A rule catches a job if its attempt falls after the job and a live applicant both exist, before the job's expiry, and at least the floor before the shift (replay estimate).

rulemisses caughtsharea week
today's 09:00 and 17:00, even with the start-time windows removed18426%15
best pair inside waking hours, 06:00 and 23:0035751%30
best pair of all, 01:00 and 06:0038855%32
hourly sweep from the first applicant44764%37
rule 1, last safe moment, 6-hour floor45264%38
rule 1 with night selections pulled to 21:59 the evening before35951%30
rule 1, 4-hour floor49270%41
rule 1, 3-hour floor51774%43

What the same rules take from hiring managers, measured on jobs managers selected themselves in the same weeks (replay estimate).

rulemanager picks the system would have made first
any two fixed clock times, windows removed49% to 54% of picks on normal jobs
hourly sweep from the first applicant85% of picks on normal jobs
rule 1, 6-hour floor0.6% on normal jobs, the same as the day-before run today; 9.5% on short-notice jobs; 2.1% overall

Reposts under rule 3 (replay estimate): of 967 clones that expired unfilled, 396 had a parent applicant who was free, meaning enabled and holding no overlapping shift. 193 of those had 6 hours or more of lead at the dropout, 244 had 3 hours or more. Of the 193, 34 were clones that never got a single applicant, so they are new value on top of rule 1.

The outlet that switched the flag off, FairPrice Xtra Changi Business Park, is the largest single block of misses. Of its 150 misses with a live applicant, rule 1 reaches 123 (82%). Turning the flag back on with today's runs reaches 65 (43%).

A second analyst, given only the timeline page, the code inventory and the data skill, reproduced the 703 misses, the three-bucket split and the ranking of schedules, and arrived at rule 1 independently: 449 of 703 caught, 2.1% of manager picks taken. The three-job difference to 452 is how the two treated the 22:00 to 23:59 blackout.

6. What the solution does not fix​

  • 251 of the 703 misses (36%) were ready less than 6 hours before the shift. Rule 1 cannot reach them at a 6-hour floor. A 3-hour floor reaches 65 more. The rest need the job to exist earlier, which is a posting and reposting question, not a selection one.
  • Auto-picked jodders complete at 66.8%, manager-picked at 78.2%, because managers reject 14.1% of automatic picks and 11.4% of those jodders cancel. Rule 5 narrows this. Closing it needs a better ranking, which is a separate piece of work.
  • 55% of rule 1's selections would happen between 00:00 and 06:59, because morning shifts reach their moment at night. Pulling those to 21:59 the evening before keeps 359 of the 452 catches. That is a product choice, recorded on the index page.

7. Build order​

  1. Rule 4, logging, and the corrected ops metric, which counts a miss only when a live eligible applicant existed at expiry. One week. Nothing after this can be measured without it.
  2. Rule 1 in the expiry command, 6-hour floor, day-before run untouched. Update the two manager emails and auto_select_schedule_time, which hard-code 09:00 and 17:00.
  3. Rule 3, carry the parent's applicants and select at once, inside the existing repost command. Fix the copied marker at the same time.
  4. Rule 5, pick quality, and the four outlets back on.
  5. Re-open instead of clone, and retire the short-notice run and the repost cron.