intermediate
rider-score
safe-ride-check
reaction-test

Reaction-Time Safe Ride Check

How the late-night reaction test works - configurable trigger window, pass criteria, cooldown, and the privacy framing.

Levy Fleets TeamMay 18, 20267 min read

Reaction-Time Safe Ride Check

The Safe Ride Check is a short reaction-time test the rider takes before unlocking during a configurable late-night window. It is designed to encourage safe decisions - it is not a sobriety or DUI test, and Levy frames it carefully both in-app and in the rental agreement.

Privacy framing - important

This is a "Safe Ride Check," not a medical or legal impairment test. The in-app copy is:

"This is not a medical or legal test of impairment. We use it to encourage safe decisions. If you do not feel safe to ride, please choose another mode of transportation."

We never share results with law enforcement except by warrant. See Appeals and Disputes for the legal framing.

What the rider does

  1. Late-night unlock attempt (default window: 22:00 to 04:00 local).
  2. The app launches a 5-round tap-the-dot mini-game. Each round spawns a dot in a random screen position; the rider taps it as fast as they can.
  3. Each round records a reaction time in milliseconds, or a "miss" if the rider does not tap inside the 3-second timeout.
  4. After 5 rounds the app computes the median reaction time and miss count.
  5. Pass: median reaction time < 450ms, fewer than 2 misses.
  6. Fail: rider sees a 30-minute unlock cooldown plus an "Are you safe to ride?" prompt with an Uber-style "Call a friend" CTA.

Pass thresholds

SettingDefaultWhat it does
reaction_median_threshold_ms450Maximum median reaction time to pass
reaction_max_misses1Maximum misses (0 or 1) to pass
reaction_test_round_count5Number of tap-the-dot rounds
reaction_test_timeout_ms3000Per-round timeout

All are per-subaccount editable at Settings > Safe Ride Check.

Trigger window

SettingDefaultWhat it does
reaction_window_start_local22:00When the check starts firing
reaction_window_end_local04:00When it stops firing (wraps midnight - handled in isWithinNightWindow)
reaction_window_enabledtrueSet false to disable Safe Ride Check entirely

The night window wrap (10pm to 4am crosses midnight) is handled in isWithinNightWindow() in src/lib/rider-score/reaction-test.ts and is unit-tested. You can also leave the window open all day if you really want, though we do not recommend it - the fail rate of a sleepy rider mid-afternoon is high enough to be unfair.

What happens on fail

A single fail:

  • 30-minute unlock cooldown on this rider's account.
  • The cooldown UI surfaces the time-remaining and a "Try again" button.
  • No score penalty.
  • No score_audit_log row, because no action was taken against the rider's tier.

Three fails in 24 hours opens a step-6 temporary lockout in the intervention ladder. This is the cross-link to the ladder - the reaction test is one of the inputs that can escalate a rider into a lockout, alongside score-based triggers.

What happens on pass

  • The rider unlocks normally.
  • A reaction_tests row is recorded with passed=true, the median, the miss count, and the trigger.
  • No effect on score or pricing.

Cooldown logic

The evaluateAttempts() kernel is unit-tested. The rules are:

reaction_tests row:
  median_reaction_ms  - median of all rounds
  miss_count          - misses (timeout &gt;= 3s)
  passed              - bool from pass criteria
  trigger             - 'nighttime' | 'appeal' | 'random'
  cooldown_until      - now + 30 min on fail

A rider whose cooldown_until is in the future is blocked from ride start by the pre-unlock gate. The block is reported as reason='reaction_cooldown'.

When else the test fires

  • Nighttime trigger (default): every unlock attempt inside the configured night window, if the rider has not passed within the last N hours (default 6).
  • Appeal trigger (optional): an operator can require a Safe Ride Check before approving a step-6 lockout appeal. This is off by default.
  • Random trigger (optional): a random subset of all unlocks (any time of day) get the test. Default 0%. Use this to catch impairment outside the night window - keep it low (1-2%).

Privacy and what we do not do

  • We do not log who the rider was talking to or what app they came from.
  • We do not record the rider's screen, camera, or microphone.
  • We do not share reaction-test results with insurers in identifiable form.
  • We do not share results with law enforcement except by warrant.
  • The 30-minute cooldown is a cooldown, not a penalty - it never reduces a rider's score.

Operator controls

  • Settings > Safe Ride Check to enable, set window, set thresholds.
  • Dashboard > Rider Score > Audit Log filtered by action='reaction_test_fail_lockout' to see who triggered a step-6 via reaction test.
  • Rider profile > Reaction tests shows the last 30 days of attempts for any given rider (useful for appeal review).

ADA and accessibility note

Reaction tests can disadvantage riders with certain disabilities. If a rider self-discloses an accessibility constraint, the operator should configure an account-level exemption at Rider profile > Exemptions. The exemption skips the reaction test entirely for that rider. This is a v3.0 manual workflow; an in-app accessibility flag is on the v3.1 roadmap.

API surface

EndpointPurpose
POST /api/mobile/rider/reaction-testSubmit attempts and get pass/fail
GET /api/mobile/rider/reaction-testIs one required right now? Returns cooldown state.

Next

See Intervention Ladder for how 3 fails in 24h become a step-6 lockout. See Appeals and Disputes if a rider believes a fail was unfair.