Spaces:
Runtime error
Runtime error
| # SPDX-License-Identifier: Apache-2.0 | |
| # Copyright 2026 DriftCall Team | |
| # Authoritative catalogue: 20 drift patterns per DESIGN.md §6.3 and | |
| # docs/modules/drift_injector.md §4.4 (5 schema + 5 policy + 5 T&C + 3 pricing | |
| # + 2 transversal payment-auth). | |
| # Every id MUST match drift_injector.md §4.4 exactly. | |
| # Every from_version / to_version MUST be a v<N>.json under data/api_schemas/<domain>/. | |
| # detection_hints are substring-matchable tokens (DESIGN.md §6.3). | |
| # --- Schema drifts (5) ------------------------------------------------------- | |
| - id: airline.price_rename | |
| drift_type: schema | |
| domain: airline | |
| from_version: v1 | |
| to_version: v2 | |
| description: "field 'price' renamed to 'total_fare_inr'; 'currency' removed" | |
| mutation: | |
| rename: {price: total_fare_inr} | |
| remove: [currency] | |
| detection_hints: | |
| - total_fare_inr | |
| - price | |
| - rename | |
| - id: airline.pax_required | |
| drift_type: schema | |
| domain: airline | |
| from_version: v2 | |
| to_version: v3 | |
| description: "booking now requires 'passenger_count' field" | |
| mutation: | |
| require_new_field: [passenger_count] | |
| detection_hints: | |
| - passenger_count | |
| - MISSING_PASSENGER_COUNT | |
| - passenger | |
| - id: cab.fare_breakdown | |
| drift_type: schema | |
| domain: cab | |
| from_version: v2 | |
| to_version: v3 | |
| description: "field 'fare_inr' replaced by nested 'fare_breakdown' with base/surge/tolls/gst" | |
| mutation: | |
| remove: [fare_inr] | |
| require_new_field: [fare_breakdown, total_inr] | |
| detection_hints: | |
| - fare_breakdown | |
| - base | |
| - surge | |
| - tolls | |
| - gst | |
| - id: restaurant.items_shape_bump | |
| drift_type: schema | |
| domain: restaurant | |
| from_version: v2 | |
| to_version: v3 | |
| description: "each item in 'items' now requires a 'modifiers' list (empty allowed)" | |
| mutation: | |
| require_new_field: [modifiers] | |
| detection_hints: | |
| - modifiers | |
| - INVALID_ITEMS_SHAPE | |
| - items | |
| - id: hotel.gst_field | |
| drift_type: schema | |
| domain: hotel | |
| from_version: v2 | |
| to_version: v3 | |
| description: "hotel.book now requires 'gst_number' when total_with_tax > 7500" | |
| mutation: | |
| require_new_field: [gst_number] | |
| detection_hints: | |
| - gst_number | |
| - MISSING_GST_NUMBER | |
| - GST_REQUIRED | |
| # --- Policy drifts (5) ------------------------------------------------------- | |
| - id: airline.booking_window_shrink | |
| drift_type: policy | |
| domain: airline | |
| from_version: v1 | |
| to_version: v2 | |
| description: "same-day bookings rejected after 14:00 IST (was: same-day always allowed)" | |
| mutation: | |
| time_window_shrink: {same_day_cutoff_hour_ist: 14} | |
| detection_hints: | |
| - BOOKING_WINDOW_CLOSED | |
| - booking_window | |
| - "14:00" | |
| - same-day | |
| - id: cab.school_hours_mini_reject | |
| drift_type: policy | |
| domain: cab | |
| from_version: v1 | |
| to_version: v2 | |
| description: "vehicle_class=mini during 07:00-09:00 IST now auto-rejects with policy_error" | |
| mutation: | |
| policy_flag_flip: {mini_reject_school_hours: true} | |
| detection_hints: | |
| - SCHOOL_HOURS_MINI_REJECTED | |
| - school_hours | |
| - mini | |
| - "07:00" | |
| - id: restaurant.min_order_bump | |
| drift_type: policy | |
| domain: restaurant | |
| from_version: v1 | |
| to_version: v2 | |
| description: "minimum order amount increased from 199 to 299" | |
| mutation: | |
| numeric_bump: {min_order_inr: 299} | |
| detection_hints: | |
| - MIN_ORDER_NOT_MET | |
| - min_order | |
| - "299" | |
| - id: hotel.cancel_window_shrink | |
| drift_type: policy | |
| domain: hotel | |
| from_version: v1 | |
| to_version: v2 | |
| description: "free cancellation window shrunk from 24h to 6h before check-in" | |
| mutation: | |
| time_window_shrink: {cancel_window_hours: 6} | |
| detection_hints: | |
| - CANCEL_WINDOW_EXPIRED | |
| - cancel_window | |
| - 6h | |
| - 24h | |
| - id: cab.vehicle_class_expand | |
| drift_type: policy | |
| domain: cab | |
| from_version: v1 | |
| to_version: v2 | |
| description: "vehicle_class enum expanded to include 'suv' and 'infant_seat_sedan'" | |
| mutation: | |
| enum_expand: | |
| vehicle_class: [mini, sedan, suv, infant_seat_sedan] | |
| detection_hints: | |
| - vehicle_class | |
| - suv | |
| - infant_seat_sedan | |
| - VEHICLE_CLASS_UNAVAILABLE | |
| # --- T&C drifts (5) --------------------------------------------------------- | |
| - id: airline.baggage_tnc_rewrite | |
| drift_type: tnc | |
| domain: airline | |
| from_version: v1 | |
| to_version: v2 | |
| description: "free cabin allowance reduced from 7kg to 5kg; announced via side-channel notice" | |
| mutation: | |
| tnc_text_swap: {cabin_allowance_kg: 5} | |
| side_channel_notice_append: "Baggage T&C updated: free cabin allowance is now 5kg (was 7kg)." | |
| detection_hints: | |
| - cabin_allowance | |
| - 5kg | |
| - 7kg | |
| - baggage | |
| - id: cab.surge_policy_tnc | |
| drift_type: tnc | |
| domain: cab | |
| from_version: v1 | |
| to_version: v2 | |
| description: "surge may now apply retroactively if ride is extended; side-channel notice" | |
| mutation: | |
| tnc_text_swap: {surge_retroactive: true} | |
| side_channel_notice_append: "Surge policy updated: retroactive surge may apply if ride is extended." | |
| detection_hints: | |
| - surge | |
| - retroactive | |
| - surge_retroactive | |
| - id: restaurant.veg_filter_semantic | |
| drift_type: tnc | |
| domain: restaurant | |
| from_version: v2 | |
| to_version: v3 | |
| description: "veg_only=True now excludes egg-based dishes (previously included)" | |
| mutation: | |
| # Two coupled keys: veg_only_excludes_egg is the new boolean policy flag | |
| # introduced in v3; veg_only is the user-facing slot whose semantics are | |
| # being mutated by this drift (same field, different meaning). Templates | |
| # tag the live slot (veg_only) — keep both so the slot_tag is targetable | |
| # AND the policy-flag audit trail is preserved. | |
| tnc_text_swap: {veg_only_excludes_egg: true, veg_only: "semantics_egg_excluded"} | |
| side_channel_notice_append: "Semantics update: veg_only=True now excludes egg-based dishes." | |
| detection_hints: | |
| - veg_only | |
| - egg | |
| - semantic | |
| - id: hotel.early_checkin_tnc | |
| drift_type: tnc | |
| domain: hotel | |
| from_version: v1 | |
| to_version: v2 | |
| description: "early check-in before 12:00 now billed at 50% of nightly rate; side-channel" | |
| mutation: | |
| tnc_text_swap: {early_checkin_fee_pct: 50} | |
| side_channel_notice_append: "Early check-in before 12:00 now costs 50% of nightly rate." | |
| detection_hints: | |
| - early_checkin | |
| - 50% | |
| - "12:00" | |
| - nightly | |
| - id: airline.reschedule_tnc | |
| drift_type: tnc | |
| domain: airline | |
| from_version: v2 | |
| to_version: v3 | |
| description: "reschedule fee previously waived; now 10% of fare + side-channel text" | |
| mutation: | |
| tnc_text_swap: {reschedule_fee_pct: 10} | |
| side_channel_notice_append: "Reschedule fee policy updated: 10% of fare applies." | |
| detection_hints: | |
| - reschedule | |
| - 10% | |
| - fare | |
| # --- Pricing drifts (3) ----------------------------------------------------- | |
| - id: airline.convenience_fee_append | |
| drift_type: pricing | |
| domain: airline | |
| from_version: v1 | |
| to_version: v2 | |
| description: "hidden 199 INR convenience fee added at booking; search estimate unchanged" | |
| mutation: | |
| fee_append: {convenience_fee_inr: 199} | |
| detection_hints: | |
| - convenience_fee | |
| - "199" | |
| - hidden | |
| - id: cab.toll_unbundle | |
| drift_type: pricing | |
| domain: cab | |
| from_version: v1 | |
| to_version: v2 | |
| description: "tolls previously included; now a separate line item on booking, not estimate" | |
| mutation: | |
| pricing_restructure: {toll_bundled: false} | |
| detection_hints: | |
| - toll | |
| - tolls | |
| - unbundle | |
| - id: hotel.resort_fee_append | |
| drift_type: pricing | |
| domain: hotel | |
| from_version: v1 | |
| to_version: v2 | |
| description: "500 INR/night resort fee added at booking; not shown in nightly_rate" | |
| mutation: | |
| fee_append: {resort_fee_inr: 500} | |
| detection_hints: | |
| - resort_fee | |
| - "500" | |
| - resort | |
| # --- Auth drifts (2, transversal via payment) ------------------------------- | |
| - id: payment.auth_scope_upgrade | |
| drift_type: auth | |
| domain: payment | |
| from_version: v1 | |
| to_version: v2 | |
| description: "token_v1 now returns 401; requires token_v2 with scope=payments:write:v2" | |
| mutation: | |
| auth_scope_bump: {required_scope: "payments:write:v2"} | |
| token_version_bump: {accepted_token_version: v2} | |
| detection_hints: | |
| - AUTH_SCOPE_INSUFFICIENT | |
| - scope | |
| - token_v2 | |
| - "payments:write:v2" | |
| - id: payment.mfa_required | |
| drift_type: auth | |
| domain: payment | |
| from_version: v1 | |
| to_version: v2 | |
| description: "transactions > 5000 INR now require mfa_code; auth_error with MFA_REQUIRED (payment v1 → v2, alternative auth-tightening to auth_scope_upgrade triggered by amount rather than scope)" | |
| mutation: | |
| policy_flag_flip: {mfa_required: true} | |
| numeric_bump: {mfa_threshold_inr: 5000} | |
| detection_hints: | |
| - MFA_REQUIRED | |
| - mfa_code | |
| - mfa | |
| - "5000" | |