File size: 8,836 Bytes
b43d8da
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# 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"