Skip to content

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