T
TOMO
Developer Docs
BETA These docs are under partner review. Some features described are roadmap items, not yet shipped. Verify against your sandbox before relying on any contract.
● DRAFTv1.0.0travel.book_cruise

travel.book_cruise — Full Intent Specification

INTENT NAMESPACE: travel
INTENT NAME:      book_cruise
FULL ID:          travel.book_cruise
VERSION:          v1.0.0
STATUS:           draft
TTBS WEIGHTS:     time 0.10 · taste 0.35 · budget 0.25 · safety 0.30
LAST UPDATED:     2026-05-14

User books a cruise voyage — domestic Indian coastal (Cordelia Cruises etc.), international (Royal Caribbean, MSC, Norwegian, Carnival, Costa, Princess), or river (Antara on Brahmaputra, Pandaw on Mekong). Multi-night sea travel with cabin accommodation, dining, on-board activities, and port-of-call shore excursions. Distinct from travel.book_package (typically land bundle), travel.book_flight (single segment), and ferry/water-taxi short-hop (not a v1 TOMO intent). Partner exemplars: Cordelia Cruises, MakeMyTrip Cruises, Thomas Cook Cruises, Cruise.com, Costa Cruises direct, Royal Caribbean partners.


1. NATURAL LANGUAGE COVERAGE

Classifies IN

  • "cruise from Mumbai"
  • "Cordelia cruise to Goa"
  • "Mediterranean cruise next year"
  • "Caribbean cruise 7 nights"
  • "river cruise Brahmaputra"
  • "Singapore Penang cruise"
  • "Royal Caribbean booking"
  • "family cruise with kids' club"
  • "cruise wedding"
  • "balcony cabin Mediterranean"

Classifies OUT — borderline NO

  • "ferry to Elephanta" — out of scope v1
  • "yacht charter for the day" — out of scope v1
  • "package tour Europe" → travel.book_package
  • "hotel in Goa" → travel.book_hotel
  • "flight to Singapore" → travel.book_flight

MULTI-INTENT TRIGGERS

  • "cruise + flight to embarkation port" → travel.book_cruise + travel.book_flight
  • "cruise + travel insurance" → travel.book_cruise + finance.buy_travel_insurance
  • "cruise + visa" → travel.book_cruise + travel.book_visa_assistance

2. INPUT — TOMO → PROVIDER

{
  "intent":          "travel.book_cruise",
  "intent_version":  "v1.0.0",
  "request_id":      "req_cru_2h4k_2026-05-14T10:00:00+05:30",
  "user_session_id": "anon_user_token_or_uid",

  "cruise_request": {
    "cruise_kind":           "ocean",
    "departure_port_city":   "Mumbai",
    "departure_port_country_code": "IN",
    "destination_themes":    ["coastal_india"],
    "destinations_must_include": [],
    "departure_window": {
      "start": "2026-11-15",
      "end":   "2026-11-25"
    },
    "duration_nights_min":   3,
    "duration_nights_max":   7,

    "party": {
      "adult_count":         2,
      "children_with_age":   [],
      "infants_under_2":     0,
      "cabins_required":     1
    },

    "preferences": {
      "cabin_kind_acceptable": ["balcony", "ocean_view"],
      "deck_preference":       "mid",
      "dining_plan":           "anytime",
      "veg_meals_priority":    true,
      "jain_meals_required":   false,
      "alcohol_package":       "non_alcoholic_package",
      "kids_club_required":    false,
      "casino_acceptable":     true,
      "smoking_section_acceptable": false,
      "wheelchair_accessibility_required": false,
      "preferred_cruise_lines": [],
      "budget_band":           "good",
      "budget_max_inr_per_person": 75000,
      "budget_max_inr_total":  150000
    }
  },

  "context": {
    "user_locale":          "en-IN",
    "user_currency_pref":   "INR",
    "trip_purpose":         "leisure",
    "trust_signals": {
      "is_repeat_customer":          false,
      "user_account_age_days":       312
    }
  }
}
Field Type Constraint Notes
intent string REQUIRED, equals "travel.book_cruise"
cruise_request.cruise_kind enum REQUIRED, STRICT §6 ocean / river / expedition
cruise_request.departure_port_city string REQUIRED Validated against partner port list
cruise_request.departure_window object REQUIRED start, end ISO_DATE
cruise_request.duration_nights_min/max int REQUIRED, 2-90
cruise_request.party.cabins_required int REQUIRED, ≥1
preferences.cabin_kind_acceptable array REQUIRED, ≥1, STRICT §6 inside / ocean_view / balcony / suite
preferences.deck_preference enum REQUIRED, STRICT §6 low / mid / high / any
preferences.dining_plan enum REQUIRED, STRICT §6 fixed_early / fixed_late / anytime / specialty_only
preferences.alcohol_package enum REQUIRED, STRICT §6 none / soft_drinks / non_alcoholic_package / alcoholic_package
preferences.kids_club_required bool REQUIRED Hard filter
preferences.wheelchair_accessibility_required bool REQUIRED Hard filter

Anti-fabrication preamble: no paid placement. International cruise lines must show Flag State + Class Society + last-inspection date. Domestic operators must show DG Shipping registration + last seaworthiness certificate.


3. PROVIDER TOOLS

Tool 1: search_cruises

PURPOSE:        return cruise voyages matching port + window + duration + cabin
INPUT:          §2 request body
OUTPUT:         { cruises: CruiseOption[], result_token, expires_at }
SLA:            p50 < 2000ms, p95 < 5000ms
RATE LIMIT:     ≤ 1/sec
RESULT SET:     up to 20 cruises

Tool 2: get_cruise_detail

PURPOSE:        full itinerary + ship facilities + cabin photos + dining
INPUT:          { cruise_id, request_id }
OUTPUT:         CruiseDetail (§5)
SLA:            p95 < 2500ms

Tool 3: hold_cabin

PURPOSE:        soft-lock cabin for 30 minutes (cruise lines hold longer)
INPUT:          { cruise_id, cabin_category_id, party, request_id }
OUTPUT:         { hold_id, hold_expires_at, locked_price_inr }
SLA:            p95 < 2500ms

Tool 4: confirm_cruise

PURPOSE:        confirm + passenger e-docs + boarding passes
INPUT:          { hold_id, passenger_passports, payment_method_id, request_id }
OUTPUT:         ConfirmedCruise (§5)
SLA:            p95 < 6000ms
IDEMPOTENCY:    request_id

Tool 5: cancel_cruise

PURPOSE:        cancel + tiered refund per cruise-line policy
INPUT:          { booking_id, reason_code, request_id }
OUTPUT:         CancellationResult (§5)
SLA:            p95 < 3500ms

4. RESPONSE SHAPE

CruiseOption

CruiseOption:
  cruise_id: { type: string, constraint: REQUIRED, opaque }
  cruise_line:
    name: { type: string, constraint: REQUIRED }
    flag_state: { type: string, constraint: REQUIRED, ISO_3166_2, semantics: "Bahamas, Italy, Malta, India etc." }
    classification_society: { type: enum, constraint: REQUIRED, STRICT §6, values: [LR, DNV, ABS, BV, IRS, RINA, ClassNK, CCS, KR, other] }
    dg_shipping_registered: { type: boolean, constraint: REQUIRED, semantics: "Mandatory TRUE for Indian-port-of-call domestic cruises" }
    last_inspection_date: { type: string, constraint: REQUIRED, ISO_DATE }
    fleet_avg_age_years: { type: float, constraint: REQUIRED, ≥0 }

  ship:
    name: { type: string, constraint: REQUIRED }
    year_built: { type: int, constraint: REQUIRED }
    year_refurbished: { type: int, constraint: REQUIRED, semantics: "= year_built if never refurbished" }
    passenger_capacity: { type: int, constraint: REQUIRED }
    crew_count: { type: int, constraint: REQUIRED }
    crew_to_passenger_ratio: { type: float, constraint: REQUIRED }
    cabin_count: { type: int, constraint: REQUIRED }
    deck_count: { type: int, constraint: REQUIRED }
    medical_facility_kind: { type: enum, constraint: REQUIRED, STRICT §6, values: [doctor_only, doctor_plus_nurse, mini_hospital] }

  voyage:
    name: { type: string, constraint: REQUIRED }
    departure_port: { type: string, constraint: REQUIRED }
    departure_datetime: { type: string, constraint: REQUIRED, ISO_DATETIME }
    return_port: { type: string, constraint: REQUIRED }
    return_datetime: { type: string, constraint: REQUIRED, ISO_DATETIME }
    duration_nights: { type: int, constraint: REQUIRED }
    ports_of_call:
      type: array<object>
      constraint: REQUIRED, may be empty
      shape:
        port: { type: string, constraint: REQUIRED }
        country_code: { type: string, constraint: REQUIRED, ISO_3166_2 }
        arrival_at: { type: string, constraint: REQUIRED, ISO_DATETIME }
        departure_at: { type: string, constraint: REQUIRED, ISO_DATETIME }
        shore_excursion_count_offered: { type: int, constraint: REQUIRED, ≥0 }

  cabin_categories:
    type: array<object>
    constraint: REQUIRED, ≥1
    shape:
      cabin_category_id: { type: string, constraint: REQUIRED }
      cabin_kind: { type: enum, constraint: REQUIRED, STRICT §6 }
      deck: { type: enum, constraint: REQUIRED, STRICT §6 }
      size_sqft: { type: int, constraint: REQUIRED }
      max_occupancy: { type: int, constraint: REQUIRED }
      photos: { type: array<string>, constraint: REQUIRED, ≥1, HTTPS URLs }
      wheelchair_accessible: { type: boolean, constraint: REQUIRED }
      price_per_person_inr: { type: int, constraint: REQUIRED, INR_INTEGER }

  pricing_summary:
    cheapest_per_person_inr: { type: int, constraint: REQUIRED, INR_INTEGER }
    selected_total_for_party_inr: { type: int, constraint: REQUIRED, INR_INTEGER }
    port_charges_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
    gst_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
    tcs_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0, semantics: "Overseas tour TCS §206C(1G)" }
    gratuities_per_person_per_day_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
    advance_payable_inr: { type: int, constraint: REQUIRED, INR_INTEGER }
    balance_due_date: { type: string, constraint: REQUIRED, ISO_DATE }

  inclusions: { type: array<enum>, constraint: REQUIRED, STRICT §6, may be empty }
  exclusions_text: { type: array<string>, constraint: REQUIRED, ≥1 }

  cancellation_policy:
    type: array<object>
    constraint: REQUIRED, may NOT be empty
    shape:
      days_before_departure_min: { type: int, constraint: REQUIRED }
      days_before_departure_max: { type: int, constraint: REQUIRED }
      cancellation_charge_pct: { type: int, constraint: REQUIRED, 0-100 }

  on_board:
    dining_venues: { type: array<string>, constraint: REQUIRED, ≥1 }
    bars_lounges: { type: array<string>, constraint: REQUIRED, may be empty }
    kids_club_present: { type: boolean, constraint: REQUIRED }
    casino_present: { type: boolean, constraint: REQUIRED }
    spa_present: { type: boolean, constraint: REQUIRED }
    pool_count: { type: int, constraint: REQUIRED, ≥0 }
    theatre_present: { type: boolean, constraint: REQUIRED }
    wifi_quality: { type: enum, constraint: REQUIRED, STRICT §6, values: [none, slow_satellite, moderate, high_speed] }
    indian_meals_available: { type: boolean, constraint: REQUIRED }
    jain_meals_available: { type: boolean, constraint: REQUIRED }
    vegetarian_full_menu: { type: boolean, constraint: REQUIRED }

  rating:
    average_score: { type: float, constraint: REQUIRED, 0.0-5.0 }
    review_count: { type: int, constraint: REQUIRED, ≥0 }

  partner_reference:
    source: { type: string, constraint: REQUIRED }
    deeplink: { type: string, constraint: REQUIRED, HTTPS URL }

CruiseDetail

CruiseDetail:
  cruise_id: { type: string, constraint: REQUIRED }
  day_by_day_plan:
    type: array<object>
    constraint: REQUIRED, length = duration_nights+1
    shape:
      day_number: { type: int, constraint: REQUIRED }
      title: { type: string, constraint: REQUIRED }
      port: { type: string, constraint: REQUIRED, semantics: "Empty when at sea" }
      arrival_at: { type: string, constraint: REQUIRED, ISO_DATETIME, semantics: "Empty when at sea" }
      departure_at: { type: string, constraint: REQUIRED, ISO_DATETIME, semantics: "Empty when at sea" }
      shore_excursions_offered: { type: array<string>, constraint: REQUIRED, may be empty }
      dining_highlights: { type: array<string>, constraint: REQUIRED, may be empty }
  ship_photos_360_url: { type: string, constraint: REQUIRED, HTTPS URL, semantics: "Empty when no 360 tour" }
  required_documents: { type: array<enum>, constraint: REQUIRED, STRICT §6, ≥1 }
  visa_advisory_text: { type: string, constraint: REQUIRED, semantics: "Empty when no visa needed" }
  health_advisory_text: { type: string, constraint: REQUIRED }
  prohibited_items_text: { type: array<string>, constraint: REQUIRED, may be empty }

ConfirmedCruise

ConfirmedCruise:
  booking_id: { type: string, constraint: REQUIRED, immutable }
  cruise_line_reference: { type: string, constraint: REQUIRED }
  ship_name: { type: string, constraint: REQUIRED }
  voyage_name: { type: string, constraint: REQUIRED }
  departure_datetime: { type: string, constraint: REQUIRED, ISO_DATETIME }
  return_datetime: { type: string, constraint: REQUIRED, ISO_DATETIME }
  cabin_assignment:
    cabin_kind: { type: enum, constraint: REQUIRED, STRICT §6 }
    deck: { type: string, constraint: REQUIRED }
    cabin_number: { type: string, constraint: REQUIRED }
  passengers:
    type: array<object>
    constraint: REQUIRED, ≥1
    shape:
      name: { type: string, constraint: REQUIRED }
      passport_number_masked: { type: string, constraint: REQUIRED, semantics: "last-4 only" }
      nationality: { type: string, constraint: REQUIRED, ISO_3166_2 }
      date_of_birth: { type: string, constraint: REQUIRED, ISO_DATE }
  total_paid_inr: { type: int, constraint: REQUIRED, INR_INTEGER }
  balance_due_inr: { type: int, constraint: REQUIRED, INR_INTEGER }
  e_ticket_url: { type: string, constraint: REQUIRED, HTTPS URL }
  boarding_pass_url: { type: string, constraint: REQUIRED, HTTPS URL, semantics: "Empty until check-in window opens" }
  embarkation_instructions_url: { type: string, constraint: REQUIRED, HTTPS URL }
  emergency_contacts:
    cruise_line_24_7_phone: { type: string, constraint: REQUIRED, E.164 }
    partner_support_phone: { type: string, constraint: REQUIRED, E.164 }
    port_agent_phone: { type: string, constraint: REQUIRED, E.164 }

CancellationResult

CancellationResult:
  booking_id: { type: string, constraint: REQUIRED }
  cancelled_at: { type: string, constraint: REQUIRED, ISO_DATETIME }
  refund_amount_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
  refund_method: { type: enum, constraint: REQUIRED, STRICT §6, values: [original_payment, bank_transfer, future_cruise_credit] }
  refund_eta_days: { type: int, constraint: REQUIRED, 0-90, semantics: "International refunds can take 60+ days" }
  cancellation_charge_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
  non_refundable_components: { type: array<string>, constraint: REQUIRED, may be empty }

FORBIDDEN FIELDS

  • paid_placement_score, ad_bid, sponsored_rank, featured_cruise_line
  • editor_pick, tomo_recommended, top_choice
  • inflated_crew_to_passenger_ratio, inflated_review_count
  • ai_generated_cabin_photo, staged_dining_photo
  • expired_classification_society_record, concealed_inspection_overdue
  • commission_padded_pricing
  • urgency_text ("Sails next week, only 1 cabin!") unless inventory truly low
  • false_indian_meal_claim — must reflect actual on-board offering

5. CONTROLLED VOCABULARIES

cruise_request.cruise_kind:
  values:
    ocean:      "Ocean / sea cruise"
    river:      "River cruise (Brahmaputra / Ganges / Mekong / Rhine / Nile)"
    expedition: "Expedition (polar / remote / small-ship adventure)"

cruise_request.destination_themes:
  values:
    coastal_india, mediterranean, caribbean, baltic, scandinavian,
    south_east_asia, japan_korea, alaska, hawaii, antarctica, arctic,
    galapagos, amazon, ganges, brahmaputra, mekong, rhine, danube, nile

cabin_kind_acceptable / cabin_kind:
  values: [inside, ocean_view, balcony, suite, garden_villa_river_expedition_only]

deck_preference / deck:
  values: [low, mid, high, any]

dining_plan:
  values: [fixed_early, fixed_late, anytime, specialty_only]

alcohol_package:
  values: [none, soft_drinks, non_alcoholic_package, alcoholic_package]

classification_society:
  values: [LR, DNV, ABS, BV, IRS, RINA, ClassNK, CCS, KR, other]

medical_facility_kind:
  values: [doctor_only, doctor_plus_nurse, mini_hospital]

wifi_quality:
  values: [none, slow_satellite, moderate, high_speed]

inclusions:
  values:
    all_meals_main_dining, gratuities_included, wifi_basic, wifi_premium,
    soft_drinks, alcohol_select, shore_excursions_select,
    speciality_dining_credit, port_charges_included, kids_club_access,
    spa_credit

CruiseDetail.required_documents:
  values:
    passport, visa, vaccination_certificate, health_questionnaire,
    travel_insurance, pcr_test_results, photo_id, parent_consent_for_minor

CancellationResult.refund_method:
  values: [original_payment, bank_transfer, future_cruise_credit]

6. TTBS DIMENSIONS

TIME (weight = 0.10):
  signals_used:
    - departure_datetime in window
    - duration fits min/max
  weighting:
    departure_fit: 0.50
    duration_fit: 0.50
  user_band_handling:
    fast: prefer earliest available
    balanced: standard
    flexible: 14-day window OK

TASTE (weight = 0.35):
  signals_used:
    - cabin_kind match
    - destinations_must_include coverage
    - cruise_line preference / DNA repeat
    - dining_plan match
    - kids_club_required (HARD when TRUE)
    - indian_meals_available / jain_meals_available match
    - on_board facilities (casino / spa / pool count)
  weighting:
    cabin_match: 0.20
    destination_match: 0.25
    line_dna: 0.20
    dining_match: 0.15
    indian_meals_fit: 0.10
    facilities_match: 0.10

BUDGET (weight = 0.25):
  signals_used:
    - pricing_summary.cheapest_per_person_inr
    - pricing_summary.selected_total_for_party_inr
    - gratuities_per_person_per_day_inr (often hidden cost)
  weighting:
    total: 0.55
    cheapest_per_person: 0.30
    gratuities: 0.15
  user_band_handling:
    ok: cheapest passing taste + safety
    good: balanced
    great: suite + premium line regardless of cost

SAFETY (weight = 0.30):
  signals_used:
    - classification_society in recognized IACS list
    - dg_shipping_registered (HARD for IN port-of-call)
    - last_inspection_date within 12 months
    - fleet_avg_age_years (lower preferred)
    - crew_to_passenger_ratio (higher preferred, ≥1:3 floor)
    - medical_facility_kind (doctor_plus_nurse floor for ocean / mini_hospital for expedition)
    - emergency_contacts complete
    - rating.average_score ≥4.0 floor
  weighting:
    class_society: 0.25
    inspection_freshness: 0.20
    crew_ratio: 0.15
    medical_facility: 0.20
    rating_floor: 0.20
  user_band_handling:
    fast: relax crew_ratio to 1:3.5
    balanced: floor 1:3
    great: mini_hospital + ≤5yr ship + IACS top-tier class

Locked weights: time 0.10 / taste 0.35 / budget 0.25 / safety 0.30. Taste leads — cruise is fundamentally an experience-fit problem. Safety is non-negotiable HARD filter (class society + DG Shipping + inspection date) before TTBS scoring runs.


7. COMPLETION CONTRACT

POST /api/v1/cpc/mcp_provider/<your_partner_id>
Body:
{
  "intent":           "travel.book_cruise",
  "external_id":      "<booking_id>",
  "request_id":       "<request_id>",
  "amount_inr":       6000,    // NET partner commission only (5-12% of voyage cost)
  "gst_inr":          1080,
  "tips_inr":         0,
  "pass_through_inr": 95000,   // remitted to cruise line (cabin + port + gratuities + meals)
  "closed_at":        "2026-11-22T11:00:00+05:30",
  "status":           "completed",
  "cruise_line":      "cordelia",
  "ship_name":        "Empress",
  "voyage_name":      "Mumbai-Goa-Mumbai",
  "duration_nights":  3,
  "cabin_kind":       "balcony",
  "passengers":       2
}

User pays full voyage cost. Partner's commission is amount_inr. Cruise-line remittance (cabin + port charges + meals + gratuities) is pass_through_inr. TCS (§206C(1G)) collected at advance-payment stage. HMAC-SHA256.


8. WIDGET

CruiseListingWidget.

Field mapping:
  - cruise_line.name + ship.name → header
  - voyage.name → subhead
  - departure_datetime → "Departs 15 Nov 7 PM"
  - duration_nights → "3 nights"
  - ports_of_call (top 4) → port chip row
  - cabin_kind selected → "Balcony cabin"
  - pricing_summary.selected_total_for_party_inr → big price
  - inclusions (top 4) → inclusion chips
  - rating.average_score + review_count → star pill
  - classification_society + flag_state → "Class: DNV · Flag: BS"
  - last_inspection_date → "Inspected Mar 2026"

9. CACHING POLICY

Call TTL Rationale
search_cruises 5min Inventory not as volatile as hotels
get_cruise_detail 30min Detail stable
hold_cabin NO CACHE Stateful lock
confirm_cruise NO CACHE Idempotent
cancel_cruise NO CACHE
Cruise-line / ship static (class, flag, inspection) 7d Updated post-inspection

10. ERROR CODES

Code HTTP Meaning Retry
INVALID_REQUEST 400 Malformed No
RATE_LIMITED 429 Throttle 1, 2s
INTERNAL_ERROR 500 Partner failure 2, exp
SIGNATURE_INVALID 401 HMAC fail No
NO_CRUISE_MATCH 200 (empty) None n/a
CABIN_TAKEN 409 Hold race-lost UI re-queries
HOLD_EXPIRED 410 Hold elapsed UI re-holds
INSPECTION_OVERDUE 422 Ship inspection lapsed; filtered No
DG_SHIPPING_NOT_REGISTERED 422 IN port-of-call without DG registration No
PAYMENT_FAILED 402 Gateway declined No
VISA_NOT_HELD 422 International voyage, visa requirement unmet No
PASSPORT_VALIDITY_INSUFFICIENT 422 Passport <6mo validity at return date No
WHEELCHAIR_NO_CABIN 422 No accessible cabin on this voyage No
CANCELLED_PAST_POLICY 410 Past full-charge stage No
VOYAGE_CANCELLED_BY_LINE 410 Line cancellation; auto-refund flow No

11. SANDBOX → PRODUCTION CHECKLIST

[ ] All five tools implemented
[ ] At least 8 cruise lines in catalog (mix of domestic + international + river)
[ ] Every classification_society in IACS members list (LR/DNV/ABS/BV/IRS/RINA/ClassNK/CCS/KR)
[ ] Every flag_state in ISO 3166-2 with valid maritime registry
[ ] DG Shipping registration verified for Indian port-of-call cruises
[ ] last_inspection_date ≤ 12 months on all ships in catalog
[ ] Crew-to-passenger ratio ≥1:3 enforced floor
[ ] medical_facility_kind floor of doctor_plus_nurse for ocean cruises
[ ] indian_meals_available / jain_meals_available flags audited (sample cruise inspection)
[ ] Wheelchair-accessible cabin availability tested
[ ] TCS §206C(1G) computed correctly at advance payment
[ ] Cancellation policy tested at multiple stages
[ ] HMAC signing verified on test CPC webhook
[ ] amount_inr in CPC is COMMISSION (NET); pass_through_inr is cruise-line remittance
[ ] All controlled vocabularies respected
[ ] No forbidden fields anywhere
[ ] SLA p95 met
[ ] Privacy policy + grievance officer + maritime liability disclosures uploaded
[ ] Customer support: 24×7 cruise helpline + emergency port agent network
[ ] Visa-advisory text validated against current MEA / cruise-destination requirements

12. ANTI-FABRICATION RULES

RULE 1: Classification society must be a current IACS member. Non-IACS
        class = ingest reject.

RULE 2: DG Shipping registration verified for Indian port-of-call;
        re-checked weekly.

RULE 3: last_inspection_date must reflect a real flag-state or class
        inspection (not partner self-attest). Re-verified at every hold.

RULE 4: crew_to_passenger_ratio must reflect official ship manifests;
        partner inflating = customer-harm + audit.

RULE 5: medical_facility_kind validated via sample audit on ship
        manifests. Partner false-flagging "mini_hospital" without facility
        = customer-harm + suspension.

RULE 6: No paid_placement, ad_bid, sponsored_rank, featured_cruise_line.

RULE 7: rating.average_score from completed voyages only; review_count
        from verified bookings only.

RULE 8: AI-generated cabin / dining photos forbidden. Real recent photos
        required; metadata audited.

RULE 9: indian_meals_available, jain_meals_available, vegetarian_full_menu
         flags must reflect actual on-board offering. Sample audits on
         maiden voyages. False = customer-harm + suspension.

RULE 10: TCS §206C(1G) computation must match Income Tax Act; under-collect
         = regulatory breach.

RULE 11: amount_inr is partner COMMISSION only. Cruise-line remittance is
         pass_through_inr. Inflated commission base = audit.

RULE 12: Voyage-line-initiated cancellations trigger automatic full
         refund within 7 days (line) + 3 days (partner) regardless of policy.

RULE 13: Required documents (passport / visa / vaccination etc.) must be
         the actual line + destination requirements. Misleading = customer
         stranded at port + reputational suspension.

RULE 14: Information-completeness score (hidden rank factor weight 0.10)
         rewards full §4 shape.

RULE 15: Gratuities-per-person-per-day must be disclosed pre-payment;
         hidden gratuities = customer-harm + audit.

RULE 16: Maritime liability disclosures (Athens Convention applicable for
         international, Indian maritime law for domestic) must be on
         partner site + linked from confirmation email.

VERSION HISTORY

v1.0.0 — 2026-05-14 — Initial spec. IACS classification + DG Shipping
                       (for IN port-of-call) + 12-month inspection floor.
                       Crew-to-passenger ≥1:3 floor. Medical-facility
                       floor doctor_plus_nurse for ocean.
                       TCS §206C(1G) compliance. Net-commission base.
                       Indian-meal / Jain-meal flags audited.