Annotation-Based Metrics¶
Metrics derived purely from human annotations on shift videos. No POS data required.
M-1: Manager Touch Count¶
Field: manager_touch_count · Type: int · Default: 0
Count of manager-at-table annotations in the session.
Formula: count(annotations where type == "manager-at-table")
M-3: Time to Drink Arrival¶
Field: time_from_session_start_to_drink_arrival_seconds · Type: int | null
Seconds from start-session to first drinks-arrived annotation.
Gate: Requires start-session annotation. Returns null without it.
Formula: max(0, drinks_arrived.time - start_session.time)
gantt
title M-3 Time to Drink Arrival
dateFormat X
axisFormat %s
section Timeline
start-session :milestone, m1, 0, 0
M-3 duration :active, 0, 120
drinks-arrived :milestone, m2, 120, 120 M-4: Waiter Touch Count¶
Field: waiter_touch_count · Type: int · Default: 0
Count of waiter-touch annotations in the session.
M-5: Hand Raise Count¶
Field: hand_raise_count · Type: int · Default: 0
Count of hand-raise annotations in the session.
M-6: Table Cleaned Time¶
Field: table_cleaned_time_seconds · Type: int | null
Seconds from end-session to the first table-cleaned annotation found in the table-level annotations (not session-level), within the window between session end and the next session start.
Gate: Requires end-session annotation. Returns null without it.
Formula: max(0, table_cleaned.time - end_session.time)
Search window: (end_session.time, next_session_start) — exclusive on both bounds. If no next session, the window extends to the end of the video.
gantt
title M-6 Table Cleaned Time
dateFormat X
axisFormat %s
section Session N
session :0, 300
end-session :milestone, m1, 300, 300
section Cleaning Window
M-6 duration :active, 300, 420
table-cleaned :milestone, m2, 420, 420
section Session N+1
next start :milestone, m3, 500, 500 M-8: First Waiter Contact Time¶
Field: first_waiter_contact_time_seconds · Type: int | null
Seconds from start-session to the first waiter-touch annotation.
Gate: Requires start-session annotation. Returns null without it.
Formula: max(0, first_waiter_touch.time - start_session.time)
M-12: Drink Delivery from Order Taken¶
Field: drink_delivery_from_order_taken_seconds · Type: int | null
Seconds from order-taken annotation to first drinks-arrived.
Gate: Requires both order-taken and drinks-arrived. No POS data needed.
Formula: max(0, drinks_arrived.time - order_taken.time)
M-13: Food Delivery from Order Taken¶
Field: food_delivery_from_order_taken_seconds · Type: int | null
Seconds from order-taken annotation to first food-arrived.
Gate: Requires both order-taken and food-arrived. No POS data needed.
Formula: max(0, food_arrived.time - order_taken.time)
M-14: Post-Payment Linger Time¶
Field: bill_payment_to_end_session_seconds · Type: int | null
Seconds from bill-payment to end-session. Measures how long guests stay after paying.
Gate: Requires both end-session and bill-payment.
Formula: max(0, end_session.time - bill_payment.time)
Note
In production, bill-payment always occurs BEFORE end-session (median -103s). The formula yields end minus bill, giving a positive value.
Annotation Event Types Reference¶
| Event Type | Kebab-case | Level | Used By |
|---|---|---|---|
| Session start | start-session | Session | M-2, M-3, M-8 |
| Session end | end-session | Session | M-6, M-14 |
| Waiter touch | waiter-touch | Session | M-4, M-8, Compliance |
| Drinks arrived | drinks-arrived | Session | M-3, M-9, M-10, M-12 |
| Food arrived | food-arrived | Session | M-7, M-11, M-13 |
| Manager at table | manager-at-table | Session | M-1 |
| Hand raise | hand-raise | Session | M-5 |
| Order taken | order-taken | Session | M-12, M-13 |
| Bill payment | bill-payment | Session | M-14 |
| Table cleaned | table-cleaned | Table | M-6 |
| No waiter touch | no-waiter-touch | Session | Compliance |