food.book_catering_event — Full Intent Specification
INTENT NAMESPACE: food
INTENT NAME: book_catering_event
FULL ID: food.book_catering_event
VERSION: v1.0.0
STATUS: draft
LAST UPDATED: 2026-05-10
TTBS WEIGHTS: time 0.20 · taste 0.40 · budget 0.20 · safety 0.20
Catering is large-scale (50+ guests typical) event meal service: corporate offsites, weddings, festivals, conferences. Differs from chef-at-home (intimate, ≤15) and dine-in (no service-at-venue): partner brings full team + equipment + serving staff to the event venue. Locked structural shape: (a) event_kind array with multi-day support; (b) service_stations enum (live counter, buffet, plated, food truck, rooftop bar); (c) equipment_provided enum (chafing dishes, serving utensils, plates, cutlery, glassware); (d) staff_breakdown block (chefs, cooks, servers, supervisors); (e) decoration_responsibility enum.
1. NATURAL LANGUAGE COVERAGE
Classifies IN
- "catering for wedding 200 guests"
- "corporate offsite catering Friday for 80 people"
- "festival catering for office 150 people"
- "conference lunch catering"
- "engagement reception catering 100 guests"
- "birthday party catering 60 people"
- "live counter catering for housewarming"
- "buffet catering for college fest"
- "food truck for kids party 50 kids"
Classifies OUT — borderline NO
- "chef at home for dinner 6 people" →
food.book_chef_at_home - "biryani delivery for office team of 12" →
food.order_delivery - "table for 20 at restaurant" →
food.book_dine_in - "tiffin for 30 employees" →
food.subscribe_tiffin(recurring)
MULTI-INTENT TRIGGERS
- "wedding catering and decoration vendor" →
food.book_catering_event+ (decoration not a TOMO intent) - "corporate catering and AV equipment rental" →
food.book_catering_event+ (rental not yet) - "festival catering and parking arrangements" →
food.book_catering_event+mobility.book_chauffeur_hourly(corporate fleet)
2. INPUT — TOMO → PROVIDER
{
"intent": "food.book_catering_event",
"intent_version": "v1.0.0",
"request_id": "req_cat_8h2k_2026-05-10T08:00:00Z",
"user_session_id": "anon_user_token_or_uid",
"event_kind": "wedding_reception",
"event_name": "Krishna-Anjali Reception",
"event_kinds_required": ["lunch_buffet", "evening_snacks", "dinner_buffet"],
"venue": {
"lat": 17.4504,
"lng": 78.3811,
"venue_name": "Banjara Palace Banquet Hall",
"address": "Road No. 12, Banjara Hills",
"neighborhood": "Banjara Hills",
"city": "Hyderabad",
"state_code": "TS",
"country_code": "IN",
"venue_kind": "banquet_hall",
"indoor_outdoor": "indoor",
"kitchen_available_at_venue": false,
"kitchen_kind_at_venue": "none",
"power_backup_available": true,
"water_supply_potable": true,
"max_capacity": 300,
"access_notes": "Loading dock at rear, freight lift to ground floor"
},
"schedule": {
"is_multi_day": false,
"scheduled_start_iso": "2026-06-15T11:00:00+05:30",
"scheduled_end_iso": "2026-06-15T23:00:00+05:30",
"service_legs": [
{
"leg_kind": "lunch_buffet",
"leg_start_iso": "2026-06-15T12:00:00+05:30",
"leg_end_iso": "2026-06-15T15:00:00+05:30",
"guest_count": 250
},
{
"leg_kind": "evening_snacks",
"leg_start_iso": "2026-06-15T17:00:00+05:30",
"leg_end_iso": "2026-06-15T19:00:00+05:30",
"guest_count": 200
},
{
"leg_kind": "dinner_buffet",
"leg_start_iso": "2026-06-15T20:00:00+05:30",
"leg_end_iso": "2026-06-15T22:30:00+05:30",
"guest_count": 250
}
]
},
"guest_profile": {
"max_guest_count": 250,
"adult_count_max": 220,
"child_count_max": 30,
"infant_count_max": 0,
"veg_count_estimate": 150,
"non_veg_count_estimate": 100,
"dietary_filters_aggregate": ["jain_count_5", "vegan_count_8", "halal_count_30"],
"allergens_to_avoid_aggregate": ["peanuts", "tree_nuts"]
},
"menu_brief": {
"cuisines_primary": ["hyderabadi", "north_indian"],
"cuisines_acceptable": ["hyderabadi", "north_indian", "south_indian", "chinese"],
"course_count_per_leg": {"lunch_buffet": 12, "evening_snacks": 8, "dinner_buffet": 16},
"live_counters_required": ["chaat", "live_dosa", "biryani_dum"],
"alcohol_serving_required": true,
"alcohol_kind": "liquor_full_bar",
"preferred_signature_dishes": ["Hyderabadi biryani", "Boondi raita", "Double ka meetha"],
"avoid_dishes": [],
"kid_friendly_section_required": true
},
"service_kind_required": ["buffet_self_serve", "live_counter", "plated_first_round"],
"decoration_responsibility": "user_provides",
"equipment_responsibility": "partner_provides",
"staff_count_minimum": 25,
"preferences": {
"budget_band": "great",
"budget_max_inr_total": 275000,
"per_head_target_inr": 1100,
"service_staff_attire": "branded_uniform",
"leftover_management_required": "donated_or_packed",
"platform_fee_transparency_required": true,
"fssai_grade_min": "A",
"kitchen_inspection_required_pre_event": true
},
"context": {
"user_locale": "en-IN",
"user_currency_pref": "INR",
"is_festival_day": false,
"is_high_demand_season": true,
"trust_signals": {
"is_repeat_customer": false,
"prior_caterings_with_partner": 0,
"user_account_age_days": 312,
"verified_phone": true
}
}
}
| Field | Type | Constraint | Notes |
|---|---|---|---|
intent |
string | REQUIRED, equals "food.book_catering_event" |
|
event_kind |
enum | REQUIRED, see §5 | |
event_name |
string | REQUIRED, may be empty | |
event_kinds_required |
array |
REQUIRED, ≥1 | drives course count per leg |
venue.venue_kind |
enum | REQUIRED, see §5 | |
venue.indoor_outdoor |
enum | REQUIRED, STRICT indoor | outdoor | both |
|
venue.kitchen_available_at_venue |
bool | REQUIRED | drives partner kitchen logistics |
venue.kitchen_kind_at_venue |
enum | REQUIRED, see §5 | |
venue.max_capacity |
int | REQUIRED, ≥1 | |
schedule.is_multi_day |
bool | REQUIRED | |
schedule.service_legs |
array | REQUIRED, ≥1 | each leg has start/end/guest count |
schedule.service_legs[].leg_kind |
enum | REQUIRED, see §5 | |
guest_profile.max_guest_count |
int | REQUIRED, ≥1 | |
guest_profile.veg_count_estimate |
int | REQUIRED, ≥0 | |
guest_profile.non_veg_count_estimate |
int | REQUIRED, ≥0 | |
guest_profile.dietary_filters_aggregate |
array |
REQUIRED, may be empty | format "tag_count_N" |
menu_brief.cuisines_primary |
array |
REQUIRED, ≥1 | |
menu_brief.course_count_per_leg |
object | REQUIRED | leg_kind → count map |
menu_brief.live_counters_required |
array |
REQUIRED, may be empty | see §5 |
menu_brief.alcohol_serving_required |
bool | REQUIRED | |
menu_brief.alcohol_kind |
enum | REQUIRED, see §5 | |
menu_brief.kid_friendly_section_required |
bool | REQUIRED | |
service_kind_required |
array |
REQUIRED, ≥1 | see §5 |
decoration_responsibility |
enum | REQUIRED, STRICT user_provides | partner_provides | third_party |
|
equipment_responsibility |
enum | REQUIRED, STRICT user_provides | partner_provides | third_party |
|
staff_count_minimum |
int | REQUIRED, ≥1 | |
preferences.fssai_grade_min |
enum | REQUIRED, STRICT A | B | C |
hard floor |
preferences.kitchen_inspection_required_pre_event |
bool | REQUIRED | |
preferences.leftover_management_required |
enum | REQUIRED, STRICT donated_or_packed | partner_disposes | user_takes_home |
Anti-fabrication preamble (universal): no paid placement, no urgency text, no commission-influenced fields.
3. PROVIDER TOOLS
Tool 1: get_catering_estimates
PURPOSE: return catering options across partners
INPUT: §2 request body
OUTPUT: { options: CateringOption[], result_token, expires_at }
SLA: p50 < 1500ms, p95 < 4000ms (catering is compute-intensive)
RATE LIMIT: ≤ 1/sec per user
Tool 2: get_partner_detail_with_menus
PURPOSE: partner profile + sample menus + past event photos
INPUT: { partner_id, request_id }
OUTPUT: CateringPartnerDetail (§4)
SLA: p95 < 1000ms
Tool 3: compute_event_quote
PURPOSE: compute total for finalized menu + staff + equipment
INPUT: { partner_id, menu_id, modifications, staff_overrides, request_id }
OUTPUT: EventQuote (§4)
SLA: p95 < 1000ms
Tool 4: book_catering_event
PURPOSE: commit booking with deposit
INPUT: { option_id, payment_token, request_id, idempotency_key, user_phone, otp_required, deposit_token }
OUTPUT: { booking_ref, status, deposit_inr, balance_due_inr, balance_due_iso, partner_arrival_window_iso }
SLA: p95 < 6000ms
IDEMPOTENCY: REQUIRED on idempotency_key
Tool 5: get_event_state
PURPOSE: live state through setup, service, teardown
INPUT: { booking_ref, request_id }
OUTPUT: CateringEventState (§4)
SLA: p95 < 800ms
RATE LIMIT: ≤ 1 every 60s during setup; ≤1/30s during service
Tool 6: cancel_catering_event
INPUT: { booking_ref, reason, request_id }
OUTPUT: { status, cancellation_charge_inr, refund_amount_inr, refund_processing_days }
SLA: p95 < 3000ms
Tool 7: request_event_modification
PURPOSE: modify guest count, add/remove leg, change menu items
INPUT: { booking_ref, modifications[], request_id }
OUTPUT: { status, fare_delta_inr, modifications_accepted, modifications_rejected }
SLA: p95 < 2000ms
Tool 8: submit_pre_event_inspection
PURPOSE: partner uploads pre-event kitchen + staff inspection report
INPUT: { booking_ref, inspection_kit, request_id }
OUTPUT: { acknowledged: true, inspection_iso, fssai_grade_observed }
SLA: p95 < 2000ms
Tool 9: confirm_event_complete
PURPOSE: record event completion + photos + leftovers
INPUT: { booking_ref, end_photos[], guests_served_actual, leftovers_donated, kitchen_cleanup_score, request_id }
OUTPUT: { acknowledged: true, completion_iso }
SLA: p95 < 2000ms
Tool 10: rate_catering_event
INPUT: { booking_ref, rating_5star, food_score, service_score, hygiene_score, presentation_score, comment, tip_inr, request_id }
OUTPUT: { acknowledged: true }
SLA: p95 < 800ms
All ten REQUIRED.
4. RESPONSE SHAPE
CateringOption
id: string, REQUIRED
option_token: string, REQUIRED
expires_at: ISO_DATETIME, REQUIRED
partner_kitchen:
id: string, REQUIRED
merchant_id: string, REQUIRED
display_name: string, REQUIRED
brand: string, REQUIRED
partner_kitchen_kind: STRICT ENUM, REQUIRED # see §5
cuisines_specialty: array<enum>, REQUIRED, ≥1
total_event_volume_30day: int, REQUIRED, ≥0
partner_account_age_days: int, REQUIRED, ≥0
trust:
fssai_license_number: string, REQUIRED
fssai_license_valid_until: ISO_DATE, REQUIRED
fssai_grade: STRICT ENUM, REQUIRED
cleanliness_audit_iso: ISO_DATETIME, REQUIRED
cleanliness_audit_score: int, REQUIRED, 0-100
food_handler_kyc_pct: int, REQUIRED, 0-100
insurance_coverage_inr: INR_INTEGER, REQUIRED
food_poisoning_coverage: boolean, REQUIRED
fire_safety_at_kitchen: boolean, REQUIRED
cold_chain_compliance: boolean, REQUIRED
catering_council_member: boolean, REQUIRED
tomo_field_team_audited: boolean, REQUIRED
ratings:
overall_score: float, REQUIRED, 0-5
overall_count: int, REQUIRED, ≥0
food_quality_score: float, REQUIRED, 0-5
service_score: float, REQUIRED, 0-5
presentation_score: float, REQUIRED, 0-5
hygiene_score: float, REQUIRED, 0-5
on_time_setup_30day_pct: float, REQUIRED, 0-1
menu:
menu_id: string, REQUIRED
menu_name: string, REQUIRED
legs: array, REQUIRED, ≥1
- leg_kind: STRICT ENUM, REQUIRED
courses: array, REQUIRED, ≥1
- course_kind: STRICT ENUM, REQUIRED
dishes: array<DishSummary>, REQUIRED, ≥1
live_counters: array<STRICT ENUM>, REQUIRED, may be empty
bar_kind: STRICT ENUM, REQUIRED # see §5; "none" if no alcohol
jain_section_supported: boolean, REQUIRED
vegan_section_supported: boolean, REQUIRED
halal_section_supported: boolean, REQUIRED
satvik_section_supported: boolean, REQUIRED
kid_friendly_section_supported: boolean, REQUIRED
staff_breakdown:
total_staff: int, REQUIRED
chefs_count: int, REQUIRED
cooks_count: int, REQUIRED
servers_count: int, REQUIRED
supervisors_count: int, REQUIRED
bartenders_count: int, REQUIRED # 0 if no bar
serving_staff_attire: STRICT ENUM, REQUIRED # see §5
staff_kyc_pct: int, REQUIRED, 0-100
staff_uniform_compliance_pct: int, REQUIRED, 0-100
equipment_provided:
chafing_dishes_count: int, REQUIRED
serving_utensils_count: int, REQUIRED
plates_count: int, REQUIRED
cutlery_sets_count: int, REQUIRED
glassware_count: int, REQUIRED
bar_setup_provided: boolean, REQUIRED
live_counter_stations_count: int, REQUIRED
food_warmers_count: int, REQUIRED
refrigeration_at_venue: boolean, REQUIRED # for cold-chain items
power_backup_at_venue_provided: boolean, REQUIRED # if user's venue lacks
decoration_supplied_in_kit: boolean, REQUIRED # basic centerpiece, etc.
logistics:
partner_arrival_iso: ISO_DATETIME, REQUIRED # how early before scheduled_start
setup_minutes_required: int, REQUIRED
teardown_minutes_required: int, REQUIRED
truck_count: int, REQUIRED, ≥1
alcohol_license_at_event_held: boolean, REQUIRED
alcohol_license_kind: STRICT ENUM, REQUIRED # see §5
alcohol_license_valid_until: ISO_DATE, REQUIRED
ice_supply_in_kit: boolean, REQUIRED
cold_storage_truck_provided: boolean, REQUIRED
fare:
total_inr: INR_INTEGER, REQUIRED
per_head_inr: INR_INTEGER, REQUIRED
food_cost_inr: INR_INTEGER, REQUIRED
staff_cost_inr: INR_INTEGER, REQUIRED
equipment_rental_inr: INR_INTEGER, REQUIRED
logistics_inr: INR_INTEGER, REQUIRED
alcohol_charge_inr: INR_INTEGER, REQUIRED
service_charge_inr: INR_INTEGER, REQUIRED
decoration_inr: INR_INTEGER, REQUIRED # 0 if user_provides
platform_fee_inr: INR_INTEGER, REQUIRED
gst_inr: INR_INTEGER, REQUIRED
fare_breakdown_text: string, REQUIRED
is_upfront_fare: boolean, REQUIRED
fare_locked_until_iso: ISO_DATETIME, REQUIRED
deposit:
required: boolean, REQUIRED
amount_inr: INR_INTEGER, REQUIRED # typically 30-50% of total
deposit_pct: float, REQUIRED, 0-1
hold_kind: STRICT ENUM, REQUIRED
balance_due_iso: ISO_DATETIME, REQUIRED # typically 7 days before event
cancellation:
free_cancel_until_iso: ISO_DATETIME, REQUIRED
cancel_charge_within_30days_inr: INR_INTEGER, REQUIRED
cancel_charge_within_7days_inr: INR_INTEGER, REQUIRED
cancel_charge_within_24h_inr: INR_INTEGER, REQUIRED
no_show_charge_inr: INR_INTEGER, REQUIRED # rare for catering
partner_cancel_compensation_inr: INR_INTEGER, REQUIRED
refund_processing_days: int, REQUIRED, ≥0
freshness:
data_last_synced_iso: ISO_DATETIME, REQUIRED
menu_last_updated_iso: ISO_DATETIME, REQUIRED
_provider:
name: string, REQUIRED
tomo_partner_id: string, REQUIRED
partner_tier: STRICT ENUM, REQUIRED
deep_link: URL, REQUIRED
customer_support_phone: string, REQUIRED
customer_support_email: string, REQUIRED
customer_support_24x7: boolean, REQUIRED
in_app_chat_supported: boolean, REQUIRED
partner_catering_volume_30d: int, REQUIRED, ≥0
partner_event_completion_rate_30d: float, REQUIRED, 0-1
partner_avg_event_size_30d: int, REQUIRED, ≥0
DishSummary
(Same structure as food.order_delivery §5 DishSummary. All fields REQUIRED.)
CateringPartnerDetail (returned by get_partner_detail_with_menus)
Superset of partner_kitchen block plus 5+ menu templates per cuisine, 20+ past event photos with consent-given user reviews, kitchen tour video URL.
EventQuote (returned by compute_event_quote)
partner_id: string, REQUIRED
menu_id: string, REQUIRED
modifications_count: int, REQUIRED, ≥0
guest_count_locked: int, REQUIRED
total_inr: INR_INTEGER, REQUIRED
per_head_inr: INR_INTEGER, REQUIRED
fare_breakdown_text: string, REQUIRED
quote_valid_until_iso: ISO_DATETIME, REQUIRED
modifications_accepted: array, REQUIRED, may be empty
modifications_rejected: array, REQUIRED, may be empty
guest_count_overage_per_head_inr: INR_INTEGER, REQUIRED # if guest count exceeds locked count
CateringEventState
booking_ref: string, REQUIRED
status: STRICT ENUM, REQUIRED # see §5
status_updated_iso: ISO_DATETIME, REQUIRED
status_history: array, REQUIRED, ≥1
setup_progress:
partner_arrived_iso: ISO_DATETIME, REQUIRED # may equal future iso
setup_pct: int, REQUIRED, 0-100
pre_event_inspection_complete: boolean, REQUIRED
inspection_grade_observed: STRICT ENUM, REQUIRED
staff_count_observed: int, REQUIRED, ≥0
service_progress:
current_leg_index: int, REQUIRED, ≥-1 # -1 between legs
guests_served_so_far: int, REQUIRED, ≥0
food_running_short_warning: boolean, REQUIRED
food_quality_observation_score: int, REQUIRED, 0-100 # partner self-report
any_food_safety_incident: boolean, REQUIRED
teardown_progress:
teardown_started_iso: ISO_DATETIME, REQUIRED # may equal future
cleanup_pct: int, REQUIRED, 0-100
leftovers_packed: boolean, REQUIRED
leftovers_donated: boolean, REQUIRED
donation_recipient_name: string, REQUIRED # may be empty
support_phone: string, REQUIRED
support_email: string, REQUIRED
Forbidden fields
paid_placement_score | sponsored_rank | promotion_priority |
fake_recent_event_text | auto_inflate_event_volume |
ai_generated_event_photo (must equal false) | hidden_logistics_fee |
fake_alcohol_license | undisclosed_food_safety_incident |
fake_partner_event_completion_rate_30d
5. CONTROLLED VOCABULARIES
event_kind
wedding | wedding_reception | engagement | sangeet | mehendi |
corporate_offsite | corporate_lunch | conference | gala_dinner |
festival_meal | religious_event_meal | birthday | anniversary |
housewarming | college_fest | school_event | charity_event |
family_reunion | community_meal | other
event_kinds_required[] and service_legs[].leg_kind
breakfast_buffet | lunch_buffet | high_tea | evening_snacks |
dinner_buffet | late_night_supper | welcome_drink_session |
cocktail_evening | dessert_only | tasting_menu_plated | brunch
venue.venue_kind
banquet_hall | hotel_ballroom | resort | farmhouse | community_hall |
office | open_lawn | rooftop | beach | boat_houseboat |
industrial_warehouse | private_residence | event_park | other
venue.indoor_outdoor
indoor | outdoor | both
venue.kitchen_kind_at_venue
none | basic_warming | full_commercial | partner_kitchen_set_up_onsite |
limited_prep_only
partner_kitchen.partner_kitchen_kind
catering_company | hotel_catering | wedding_specialist |
corporate_catering | community_kitchen_co_op | celebrity_chef_catering |
food_truck_catering | mobile_kitchen
cuisines_*
hyderabadi | south_indian | north_indian | bengali | punjabi | gujarati |
maharashtrian | rajasthani | kerala | tamilian | andhra | konkani | goan |
chinese | thai | korean | japanese | sushi | italian | french | continental |
mediterranean | mexican | lebanese | turkish | greek | mughlai | awadhi |
kashmiri | jain | satvik | live_grill | bbq | tandoor | chaat | fusion |
multi_cuisine_buffet
course_kind
welcome_drink | appetizer | starter | soup | salad | bread |
main | side | rice | biryani | pasta_or_noodle | dessert |
beverage | tea_coffee | dessert_buffet | mithai_section
live_counters_required[] and live_counters[]
chaat | live_dosa | live_pasta | live_pizza | live_grill | tandoor_live |
biryani_dum | live_chinese_wok | live_pasta | mocktail_counter |
juice_bar | salad_bar | sushi_bar | live_kebab | tava_paratha |
ice_cream_counter | dessert_counter | paan_counter | filter_coffee_counter
bar_kind and menu_brief.alcohol_kind
none | beer_only | wine_only | beer_wine | liquor_full_bar |
premium_full_bar | bar_specialty_cocktails
service_kind_required[]
buffet_self_serve | live_counter | plated_first_round | family_style |
food_truck | rooftop_bar | passed_appetizers | tasting_menu
staff_breakdown.serving_staff_attire
branded_uniform | chef_whites | smart_casual | traditional_indian |
formal_wear | event_specific_costume
partner_kitchen.trust.fssai_grade
A | B | C | unrated
dietary_filters_aggregate[] (special format)
veg_count_N | non_veg_count_N | egg_count_N | vegan_count_N |
jain_count_N | halal_count_N | satvik_count_N |
gluten_free_count_N | low_carb_count_N
allergens_to_avoid_aggregate[]
peanuts | tree_nuts | dairy | eggs | wheat | gluten | soy |
fish | shellfish | sesame
equipment_responsibility and decoration_responsibility
user_provides | partner_provides | third_party
logistics.alcohol_license_kind
none | event_l_19 | bar_l_19 | restaurant_l_3 | wine_l_24 |
beer_only | full_bar | one_day_event_permit
deposit.hold_kind
card_block | bank_transfer | wallet_hold | partial_advance | full_advance
CateringEventState.status
booked | confirmed | partner_assigned | inspection_pending |
inspection_complete | partner_en_route | partner_arrived |
setup_in_progress | service_leg_1 | between_legs |
service_leg_n | event_complete_teardown | teardown_complete |
fully_complete | cancelled_by_user | cancelled_by_partner |
incident_open | failed
CateringEventState.setup_progress.inspection_grade_observed
A | B | C | unrated
dish.veg_or_non_veg
veg | non_veg | egg | vegan | jain
dish.spice_level
mild | medium | spicy | very_spicy
dish.oil_used
sunflower | mustard | groundnut | rice_bran | olive | coconut |
ghee | butter | palm | mixed | none
cancel_catering_event.reason
user_changed_plans | postponed_event | cancelled_event | venue_unavailable |
weather_block | budget_changed | found_alternative | medical | other
preferences.leftover_management_required
donated_or_packed | partner_disposes | user_takes_home
merchant_id resolution order
1. FSSAI license number
2. partner_id + ":" + kitchen_id
3. Google Place ID (if partner has fixed kitchen)
6. TTBS DIMENSIONS
Per-domain weights
food (book_catering_event): { time: 0.20, taste: 0.40, budget: 0.20, safety: 0.20 }
TIME
SIGNALS USED:
- logistics.partner_arrival_iso ≤ scheduled_start - setup_minutes_required HARD FILTER
- partner_kitchen.ratings.on_time_setup_30day_pct weight 0.40
- logistics.setup_minutes_required (lower=better) weight 0.20
- cancellation.refund_processing_days weight 0.10
- service_legs scheduling feasibility validated HARD FILTER
TASTE
SIGNALS USED:
- partner_kitchen.ratings.food_quality_score weight 0.20
- partner_kitchen.ratings.presentation_score weight 0.20
- partner_kitchen.ratings.recent_30day_score weight 0.15
- menu cuisine match user.cuisines_primary weight 0.20
- menu.live_counters_required all supported HARD FILTER (or partial filter)
- menu jain/halal/vegan sections support user dietary HARD FILTER
HARD FILTERS:
- jain_section needed AND jain_section_supported=false
- halal_section needed AND halal_section_supported=false
- kid_friendly_section_required AND kid_friendly_section_supported=false
- alcohol_serving_required AND alcohol_license_at_event_held=false
- allergens_to_avoid present in menu
BUDGET
SIGNALS USED:
- per_head_inr vs band:
ok → 0–33rd percentile (cuisine, city, event_kind)
good → 33rd–66th
great → 66th+
- fare.is_upfront_fare=true weight 0.20
- guest_count_overage_per_head_inr (lower=better) weight 0.20
- deposit.deposit_pct (lower=better, all else equal) weight 0.15
- cancellation tier permissiveness weight 0.15
- decoration_inr included if responsibility=partner weight 0.10
- platform_fee_inr (lower=better) weight 0.10
HARD FILTERS:
- fare.total_inr > preferences.budget_max_inr_total → drop
SAFETY
SIGNALS USED:
- partner_kitchen.trust.fssai_grade ≥ preferences.fssai_grade_min HARD FILTER
- partner_kitchen.trust.cleanliness_audit_score weight 0.25
- partner_kitchen.trust.food_handler_kyc_pct (≥80) weight 0.15
- partner_kitchen.trust.fire_safety_at_kitchen HARD FILTER
- partner_kitchen.trust.cold_chain_compliance weight 0.15
- partner_kitchen.trust.food_poisoning_coverage weight 0.20
- partner_kitchen.trust.insurance_coverage_inr (≥1000K large events) weight 0.15
- partner_kitchen.trust.tomo_field_team_audited weight 0.10
- staff_breakdown.staff_kyc_pct (≥90) weight 0.10
- staff_breakdown.staff_uniform_compliance_pct (≥90) weight 0.05
- menu_brief.alcohol_serving_required AND alcohol_license_kind invalid HARD FILTER
- is_outdoor_venue → safety scales 1.2x (weather/sanitation risk)
HARD FILTERS:
- kitchen_inspection_required_pre_event AND partner doesn't support → drop
- alcohol_serving_required AND alcohol license missing → drop
Hidden ranking factor
information_completeness_score weight 0.10.
7. COMPLETION CONTRACT
POST /api/v1/cpc/mcp_provider/{tomo_partner_id}
{
"intent": "food.book_catering_event",
"intent_version": "v1.0.0",
"external_id": "CATER-XYZ",
"amount_inr": 268000,
"closed_at": "2026-06-15T23:30:00+05:30",
"request_id": "req_cat_8h2k_...",
"status": "completed",
"booking_ref": "CATER-XYZ",
"event_started_at": "2026-06-15T11:00:00+05:30",
"event_completed_at": "2026-06-15T22:30:00+05:30",
"guests_served_actual": 248,
"guest_count_overage_inr": 0,
"service_legs_completed": 3,
"any_food_safety_incident": false,
"leftovers_donated": true,
"donation_recipient_name": "Robin Hood Army Hyderabad",
"kitchen_cleanup_score": 95,
"currency": "INR",
"fare_breakdown_total_inr": 268000,
"rider_tip_inr": 5000,
"ratings_pending": true,
"notes": ""
}
Status enum: completed | cancelled_by_user | cancelled_by_partner | failed | partial_completion_event_cut_short | terminated_with_food_safety_incident | terminated_with_alcohol_license_violation
8. WIDGET
WIDGET TYPE: catering_event_options
SOURCE: src/widgets/types.ts
TYPE NAME: CateringEventOptionsPayload
RENDERED IN: components/widgets/CateringEventOptionsWidget.tsx
Default: 3 stacked rows showing partner name, cuisine specialty, per-head price, FSSAI grade badge, on-time-setup-rate. Tap row → partner detail with menu carousel + past event photos + reviews → "Book event". Then CateringDashboard with setup progress + service leg timeline + teardown.
9. CACHING POLICY
| Call | TTL | Rationale |
|---|---|---|
get_catering_estimates |
600s | catering quotes change slowly |
get_partner_detail_with_menus |
5min | menus rarely shift |
compute_event_quote |
5min | quote_valid_until_iso enforced |
book_catering_event |
0s | |
get_event_state |
30s | live during event |
| Failure responses | 0s |
10. ERROR CODES
| Code | HTTP | Meaning | TOMO behavior |
|---|---|---|---|
NO_PARTNERS_AVAILABLE |
503 | no partner matches | retry or fall back |
OUT_OF_SERVICE_AREA |
400 | venue outside coverage | surface |
OPTION_EXPIRED |
410 | option_token invalid | re-quote |
MENU_INFEASIBLE |
400 | menu impossible at venue | surface |
ALCOHOL_LICENSE_INVALID |
503 | license expired or wrong kind | surface alternate |
BOOKING_NOT_FOUND |
404 | booking_ref doesn't exist | surface |
ALREADY_CANCELLED |
409 | duplicate cancel | idempotent |
INSPECTION_FAILED |
503 | pre-event inspection found violations | surface decision flow |
STAFF_KYC_INSUFFICIENT |
503 | staff KYC % below floor | surface alternate |
GUEST_COUNT_EXCEEDS_VENUE_CAPACITY |
400 | venue.max_capacity exceeded | surface |
INGREDIENT_LOGISTICS_FAILED |
503 | partner cannot source ingredients | surface |
11. SANDBOX → PRODUCTION CHECKLIST
[ ] All §2 inputs validated, request_id echoed
[ ] get_catering_estimates returns ≥3 options for "wedding 200 guests Hyderabad"
[ ] All §4 fields populated with REAL data
[ ] FSSAI license + grade present + valid through event date
[ ] Insurance coverage ≥1000K verified for large events
[ ] alcohol_license_at_event_held tested if alcohol_serving_required
[ ] photo_ai_generated == false everywhere
[ ] book_catering_event returns booking_ref + balance_due schedule
[ ] Pre-event inspection flow tested with photo upload
[ ] get_event_state returns setup_pct in real time
[ ] cancel respects cancellation tiers (30day, 7day, 24h)
[ ] CPC webhook arrives within 60s of completion
[ ] HMAC verification passes
[ ] No forbidden fields anywhere
[ ] No paid placement / sponsored signals
[ ] customer_support_24x7 verified by TOMO field call
[ ] Insurance certificate uploaded for liability claims
[ ] Staff KYC artifacts uploaded for sample staff
[ ] Sample menu photos verified non-AI
[ ] Catering council membership verified (if claimed)
12. ANTI-FABRICATION RULES
RULE 1 — No paid placement signals.
RULE 2 — Ratings unrounded floats from verified events only.
RULE 3 — No fake event volume or completion rate inflation.
TOMO compares stated vs partner CPC ledger; >5% mismatch = breach.
RULE 4 — No AI-generated event photos.
RULE 5 — Alcohol license must be valid AT event date.
Booking with license expired before scheduled_end_iso = severe compliance breach.
RULE 6 — FSSAI grade real and current.
Grade A claim must match latest published FSSAI inspection. Self-elevating
to attract premium events = breach.
RULE 7 — Insurance coverage real.
RULE 8 — Food poisoning coverage actually pays.
food_poisoning_coverage=true must trigger partner liability + medical
reimbursement. Suppressing or refusing claims = severe breach.
RULE 9 — No commission-based response shaping.
RULE 10 — Pre-event inspection cannot be skipped if required.
kitchen_inspection_required_pre_event=true means partner submits inspection
≥48h before event. Skipping = breach.
RULE 11 — Staff count honored.
staff_count delivered must match contracted count. Showing up with 18
when 25 was contracted = breach + automatic refund tier.
RULE 12 — No fake ingredients sourcing.
Partner cannot substitute "fresh paneer" with cottage cheese mix without
user notification. Substitution requires user consent.
RULE 13 — Leftover management honored.
leftover_management_required=donated_or_packed means leftovers actually
reach a verifiable food bank or are packed for user. Disposing leftovers
silently = breach.
RULE 14 — Food safety incidents must be reported.
Suppressing reported food poisoning post-event to preserve completion
rate = severe breach + criminal exposure.
RULE 15 — Equipment provided as advertised.
equipment_provided counts must match physical reality. Showing up with
10 chafing dishes when 18 contracted = breach.
RULE 16 — No bait-and-switch on chefs.
Headline chef in marketing must actually attend the event for ≥50% of
service hours. Substituting silently = breach.
VERSION HISTORY
v1.0.0 — 2026-05-10 — Initial spec