@shipeasy/openapi 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/{chunk-EPLLHLZN.js → chunk-LYNWK55D.js} +23 -1
  2. package/dist/chunk-LYNWK55D.js.map +1 -0
  3. package/dist/{chunk-SPH5HWCD.js → chunk-PRN4AEAM.js} +396 -187
  4. package/dist/chunk-PRN4AEAM.js.map +1 -0
  5. package/dist/{client-pVkoo3Bf.d.ts → client-DO5HTb_L.d.ts} +886 -241
  6. package/dist/client.d.ts +1 -1
  7. package/dist/client.js +7 -1
  8. package/dist/custom.d.ts +23 -1
  9. package/dist/custom.js +12 -4
  10. package/dist/custom.js.map +1 -1
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.js +8 -2
  13. package/dist/index.js.map +1 -1
  14. package/dist/schemas.d.ts +770 -104
  15. package/dist/schemas.js +57 -5
  16. package/openapi.json +2177 -775
  17. package/openapi.yaml +1373 -409
  18. package/package.json +1 -1
  19. package/spec/components/errors.yaml +30 -1
  20. package/spec/components/parameters.yaml +8 -0
  21. package/spec/components/responses.yaml +15 -0
  22. package/spec/components/schemas/common.yaml +11 -0
  23. package/spec/components/schemas/connectors.yaml +5 -11
  24. package/spec/components/schemas/errors-api.yaml +66 -3
  25. package/spec/components/schemas/experiment-api-row.yaml +293 -0
  26. package/spec/components/schemas/experiments.yaml +54 -299
  27. package/spec/components/schemas/gate-templates.yaml +41 -2
  28. package/spec/components/schemas/gates.yaml +19 -0
  29. package/spec/components/schemas/keys.yaml +2 -1
  30. package/spec/components/schemas/metrics.yaml +17 -17
  31. package/spec/components/schemas/ops.yaml +105 -2
  32. package/spec/components/schemas/projects.yaml +119 -1
  33. package/spec/components/schemas/universes.yaml +83 -1
  34. package/spec/openapi.yaml +35 -2
  35. package/spec/paths/alert-rules.yaml +11 -2
  36. package/spec/paths/attributes.yaml +14 -3
  37. package/spec/paths/configs.yaml +24 -9
  38. package/spec/paths/connectors.yaml +42 -8
  39. package/spec/paths/errors.yaml +100 -6
  40. package/spec/paths/events.yaml +19 -4
  41. package/spec/paths/experiments.yaml +45 -11
  42. package/spec/paths/gate-templates.yaml +9 -5
  43. package/spec/paths/gates.yaml +21 -6
  44. package/spec/paths/i18n.yaml +18 -5
  45. package/spec/paths/keys.yaml +3 -1
  46. package/spec/paths/killswitches.yaml +24 -6
  47. package/spec/paths/metrics.yaml +15 -3
  48. package/spec/paths/ops.yaml +114 -3
  49. package/spec/paths/projects.yaml +3 -3
  50. package/spec/paths/universes.yaml +11 -2
  51. package/dist/chunk-EPLLHLZN.js.map +0 -1
  52. package/dist/chunk-SPH5HWCD.js.map +0 -1
@@ -4,149 +4,7 @@ ListExperimentsResponse:
4
4
  data:
5
5
  type: array
6
6
  items:
7
- type: object
8
- properties:
9
- id:
10
- type: string
11
- description: Stable opaque experiment id (`exp_…`).
12
- name:
13
- type: string
14
- maxLength: 128
15
- pattern: ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$
16
- description: Stable experiment key. Single segment or `folder.name` (a-z, 0-9, `_`/`-`; max 128 chars). Used by SDKs as `Shipeasy.getExperiment(user, '<name>')`. Immutable after create.
17
- description:
18
- anyOf:
19
- - type: string
20
- - type: "null"
21
- hypothesis:
22
- anyOf:
23
- - type: string
24
- - type: "null"
25
- tag:
26
- anyOf:
27
- - type: string
28
- - type: "null"
29
- ownerEmail:
30
- anyOf:
31
- - type: string
32
- - type: "null"
33
- audience:
34
- anyOf:
35
- - type: string
36
- - type: "null"
37
- bucketBy:
38
- anyOf:
39
- - type: string
40
- minLength: 1
41
- maxLength: 128
42
- pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
43
- description: User-attribute name used as the bucketing key — e.g. `user_id` (default), `session_id`, `device_id`, or a custom attribute like `company_id` to keep a whole org on one variant. Defaults to `user_id` when omitted.
44
- - type: "null"
45
- folder:
46
- anyOf:
47
- - type: string
48
- - type: "null"
49
- status:
50
- type: string
51
- enum:
52
- - draft
53
- - running
54
- - stopped
55
- - archived
56
- universe:
57
- type: string
58
- description: Universe name this experiment draws from.
59
- targetingGate:
60
- anyOf:
61
- - type: string
62
- - type: "null"
63
- allocationPct:
64
- type: integer
65
- minimum: -9007199254740991
66
- maximum: 9007199254740991
67
- description: Allocation in basis points (0–10000).
68
- salt:
69
- type: string
70
- params:
71
- type: object
72
- additionalProperties:
73
- type: string
74
- enum:
75
- - string
76
- - bool
77
- - number
78
- groups:
79
- type: array
80
- items:
81
- type: object
82
- properties:
83
- name:
84
- type: string
85
- minLength: 1
86
- maxLength: 64
87
- description: Group label (e.g. `control`, `treatment_a`). Max 64 chars.
88
- weight:
89
- type: integer
90
- minimum: 0
91
- maximum: 10000
92
- description: Allocation weight in basis points (0–10000). The sum across all groups must equal exactly **10000** (100%).
93
- params:
94
- default: {}
95
- description: Per-group parameter values delivered to the SDK when a caller is hashed into this group. Keys must match the experiment's `params` schema.
96
- type: object
97
- additionalProperties: {}
98
- required:
99
- - name
100
- - weight
101
- additionalProperties: false
102
- description: One variant in the experiment. Weights across all groups must sum to 10000.
103
- significanceThreshold:
104
- type: number
105
- minRuntimeDays:
106
- type: integer
107
- minimum: -9007199254740991
108
- maximum: 9007199254740991
109
- minSampleSize:
110
- type: integer
111
- minimum: -9007199254740991
112
- maximum: 9007199254740991
113
- sequentialTesting:
114
- type: boolean
115
- startedAt:
116
- anyOf:
117
- - type: string
118
- - type: "null"
119
- description: ISO-8601 timestamp the experiment last transitioned to `running`, or `null`.
120
- stoppedAt:
121
- anyOf:
122
- - type: string
123
- - type: "null"
124
- updatedAt:
125
- type: string
126
- required:
127
- - id
128
- - name
129
- - description
130
- - hypothesis
131
- - tag
132
- - ownerEmail
133
- - audience
134
- - bucketBy
135
- - folder
136
- - status
137
- - universe
138
- - targetingGate
139
- - allocationPct
140
- - salt
141
- - params
142
- - groups
143
- - significanceThreshold
144
- - minRuntimeDays
145
- - minSampleSize
146
- - sequentialTesting
147
- - startedAt
148
- - updatedAt
149
- additionalProperties: false
7
+ $ref: ./experiment-api-row.yaml#/ExperimentApiRow
150
8
  next_cursor:
151
9
  anyOf:
152
10
  - type: string
@@ -156,149 +14,7 @@ ListExperimentsResponse:
156
14
  - next_cursor
157
15
  additionalProperties: false
158
16
  GetExperimentResponse:
159
- type: object
160
- properties:
161
- id:
162
- type: string
163
- description: Stable opaque experiment id (`exp_…`).
164
- name:
165
- type: string
166
- maxLength: 128
167
- pattern: ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$
168
- description: Stable experiment key. Single segment or `folder.name` (a-z, 0-9, `_`/`-`; max 128 chars). Used by SDKs as `Shipeasy.getExperiment(user, '<name>')`. Immutable after create.
169
- description:
170
- anyOf:
171
- - type: string
172
- - type: "null"
173
- hypothesis:
174
- anyOf:
175
- - type: string
176
- - type: "null"
177
- tag:
178
- anyOf:
179
- - type: string
180
- - type: "null"
181
- ownerEmail:
182
- anyOf:
183
- - type: string
184
- - type: "null"
185
- audience:
186
- anyOf:
187
- - type: string
188
- - type: "null"
189
- bucketBy:
190
- anyOf:
191
- - type: string
192
- minLength: 1
193
- maxLength: 128
194
- pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
195
- description: User-attribute name used as the bucketing key — e.g. `user_id` (default), `session_id`, `device_id`, or a custom attribute like `company_id` to keep a whole org on one variant. Defaults to `user_id` when omitted.
196
- - type: "null"
197
- folder:
198
- anyOf:
199
- - type: string
200
- - type: "null"
201
- status:
202
- type: string
203
- enum:
204
- - draft
205
- - running
206
- - stopped
207
- - archived
208
- universe:
209
- type: string
210
- description: Universe name this experiment draws from.
211
- targetingGate:
212
- anyOf:
213
- - type: string
214
- - type: "null"
215
- allocationPct:
216
- type: integer
217
- minimum: -9007199254740991
218
- maximum: 9007199254740991
219
- description: Allocation in basis points (0–10000).
220
- salt:
221
- type: string
222
- params:
223
- type: object
224
- additionalProperties:
225
- type: string
226
- enum:
227
- - string
228
- - bool
229
- - number
230
- groups:
231
- type: array
232
- items:
233
- type: object
234
- properties:
235
- name:
236
- type: string
237
- minLength: 1
238
- maxLength: 64
239
- description: Group label (e.g. `control`, `treatment_a`). Max 64 chars.
240
- weight:
241
- type: integer
242
- minimum: 0
243
- maximum: 10000
244
- description: Allocation weight in basis points (0–10000). The sum across all groups must equal exactly **10000** (100%).
245
- params:
246
- default: {}
247
- description: Per-group parameter values delivered to the SDK when a caller is hashed into this group. Keys must match the experiment's `params` schema.
248
- type: object
249
- additionalProperties: {}
250
- required:
251
- - name
252
- - weight
253
- additionalProperties: false
254
- description: One variant in the experiment. Weights across all groups must sum to 10000.
255
- significanceThreshold:
256
- type: number
257
- minRuntimeDays:
258
- type: integer
259
- minimum: -9007199254740991
260
- maximum: 9007199254740991
261
- minSampleSize:
262
- type: integer
263
- minimum: -9007199254740991
264
- maximum: 9007199254740991
265
- sequentialTesting:
266
- type: boolean
267
- startedAt:
268
- anyOf:
269
- - type: string
270
- - type: "null"
271
- description: ISO-8601 timestamp the experiment last transitioned to `running`, or `null`.
272
- stoppedAt:
273
- anyOf:
274
- - type: string
275
- - type: "null"
276
- updatedAt:
277
- type: string
278
- required:
279
- - id
280
- - name
281
- - description
282
- - hypothesis
283
- - tag
284
- - ownerEmail
285
- - audience
286
- - bucketBy
287
- - folder
288
- - status
289
- - universe
290
- - targetingGate
291
- - allocationPct
292
- - salt
293
- - params
294
- - groups
295
- - significanceThreshold
296
- - minRuntimeDays
297
- - minSampleSize
298
- - sequentialTesting
299
- - startedAt
300
- - updatedAt
301
- additionalProperties: false
17
+ $ref: ./experiment-api-row.yaml#/ExperimentApiRow
302
18
  CreateExperimentRequest:
303
19
  type: object
304
20
  properties:
@@ -359,13 +75,19 @@ CreateExperimentRequest:
359
75
  description: Name of an existing universe in the project. Returns `422` if the universe doesn't exist.
360
76
  targeting_gate:
361
77
  default: null
362
- description: Optional gate name. Only callers that pass the gate are enrolled in the experiment.
78
+ description: Optional gate name (a `targeting`-type flag). Only callers that pass the gate are enrolled in the experiment.
79
+ anyOf:
80
+ - type: string
81
+ - type: "null"
82
+ holdout_gate:
83
+ default: null
84
+ description: Optional per-experiment holdout gate — the name of a `holdout`-type flag (public % + whitelist). A caller the flag passes is *held out* (never assigned, sees the universe defaults). Distinct from the universe-level holdout.
363
85
  anyOf:
364
86
  - type: string
365
87
  - type: "null"
366
88
  allocation_pct:
367
89
  default: 0
368
- description: Share of the (gated) audience allocated to the experiment, in basis points (0–10000 = 0%–100%). `0` = unallocated. Use `allocation_percent` (0–100) below to think in percent. Immutable while the experiment is running.
90
+ description: Share of the (gated) audience allocated to the experiment, in basis points (0–10000 = 0%–100%). `0` = unallocated. Under pooled assignment this is the size of the universe-pool slice claimed. Use `allocation_percent` (0–100) below to think in percent. Immutable while the experiment is running.
369
91
  type: integer
370
92
  minimum: 0
371
93
  maximum: 10000
@@ -374,6 +96,11 @@ CreateExperimentRequest:
374
96
  type: number
375
97
  minimum: 0
376
98
  maximum: 100
99
+ reserved_headroom:
100
+ description: Basis points of this experiment's split kept empty (0–10000) so a new variant can be appended into it while running without reshuffling. Group weights must sum to `10000 − reserved_headroom`. Defaults to the universe's `recommended_headroom` when omitted.
101
+ type: integer
102
+ minimum: 0
103
+ maximum: 10000
377
104
  salt:
378
105
  description: Hash salt for bucketing. Auto-generated if omitted. Immutable while running.
379
106
  type: string
@@ -388,7 +115,7 @@ CreateExperimentRequest:
388
115
  - string
389
116
  - bool
390
117
  - number
391
- description: "Map of param-name → scalar type. Defines the shape of `groups[].params`. Example: `{ headline: 'string', show_cta: 'bool' }`."
118
+ description: "**Deprecated** — the universe now owns the config schema (`param_schema`). Retained for back-compat; new experiments should leave this empty and declare params on the universe. Map of param-name → scalar type."
392
119
  groups:
393
120
  minItems: 2
394
121
  type: array
@@ -404,18 +131,18 @@ CreateExperimentRequest:
404
131
  type: integer
405
132
  minimum: 0
406
133
  maximum: 10000
407
- description: Allocation weight in basis points (0–10000). The sum across all groups must equal exactly **10000** (100%).
134
+ description: Allocation weight in basis points (0–10000). Weights across all groups must sum to `10000 − reserved_headroom` (100% minus any reserved tail).
408
135
  params:
409
136
  default: {}
410
- description: Per-group parameter values delivered to the SDK when a caller is hashed into this group. Keys must match the experiment's `params` schema.
137
+ description: Per-variant **override map** — a subset of the universe's `param_schema` keys. A key the variant doesn't set inherits the universe default. Unknown keys (not in the universe schema) are rejected.
411
138
  type: object
412
139
  additionalProperties: {}
413
140
  required:
414
141
  - name
415
142
  - weight
416
143
  additionalProperties: false
417
- description: One variant in the experiment. Weights across all groups must sum to 10000.
418
- description: Two or more variants. Weights must sum to exactly 10000 (100%). Immutable while running.
144
+ description: One variant. Its `params` may only override keys declared on the universe schema.
145
+ description: Two or more variants. Weights must sum to `10000 − reserved_headroom`. Existing weights are immutable while running, but a new variant may be appended into the reserved tail.
419
146
  significance_threshold:
420
147
  default: 0.05
421
148
  description: p-value cutoff used by the analysis pass. Defaults to `0.05`. Values other than 0.05 require Pro plan or higher.
@@ -516,11 +243,21 @@ UpdateExperimentRequest:
516
243
  anyOf:
517
244
  - type: string
518
245
  - type: "null"
246
+ holdout_gate:
247
+ description: Per-experiment holdout gate — the name of a `holdout`-type flag, or `null` to clear. A caller the flag passes is held out.
248
+ anyOf:
249
+ - type: string
250
+ - type: "null"
519
251
  allocation_pct:
520
252
  description: Basis-points allocation (0–10000). Use `allocation_percent` (0–100) for percent. Immutable while the experiment is running.
521
253
  type: integer
522
254
  minimum: 0
523
255
  maximum: 10000
256
+ reserved_headroom:
257
+ description: Basis points of the split kept empty for appended variants. Group weights must sum to `10000 − reserved_headroom`. May be shrunk (never grown into existing weights) while running when appending a variant.
258
+ type: integer
259
+ minimum: 0
260
+ maximum: 10000
524
261
  allocation_percent:
525
262
  description: Allocation as a **percentage** (0–100). Friendlier alias for `allocation_pct`; converted to basis points server-side. Wins over `allocation_pct` if both are supplied. Immutable while running.
526
263
  type: number
@@ -542,9 +279,9 @@ UpdateExperimentRequest:
542
279
  - string
543
280
  - bool
544
281
  - number
545
- description: "Map of param-name → scalar type. Defines the shape of `groups[].params`. Example: `{ headline: 'string', show_cta: 'bool' }`."
282
+ description: "**Deprecated** — the universe owns the config schema (`param_schema`). Retained for back-compat. Map of param-name → scalar type."
546
283
  groups:
547
- description: Replacement groups. Weights must sum to 10000. Immutable while running.
284
+ description: Replacement groups. Weights must sum to `10000 − reserved_headroom`. Existing weights/values are immutable while running; a new variant may be appended into the reserved tail.
548
285
  minItems: 2
549
286
  type: array
550
287
  items:
@@ -559,17 +296,17 @@ UpdateExperimentRequest:
559
296
  type: integer
560
297
  minimum: 0
561
298
  maximum: 10000
562
- description: Allocation weight in basis points (0–10000). The sum across all groups must equal exactly **10000** (100%).
299
+ description: Allocation weight in basis points (0–10000). Weights across all groups must sum to `10000 − reserved_headroom`.
563
300
  params:
564
301
  default: {}
565
- description: Per-group parameter values delivered to the SDK when a caller is hashed into this group. Keys must match the experiment's `params` schema.
302
+ description: Per-variant **override map** — a subset of the universe's `param_schema` keys. Unknown keys are rejected; unset keys inherit the universe default.
566
303
  type: object
567
304
  additionalProperties: {}
568
305
  required:
569
306
  - name
570
307
  - weight
571
308
  additionalProperties: false
572
- description: One variant in the experiment. Weights across all groups must sum to 10000.
309
+ description: One variant. Its `params` may only override keys declared on the universe schema.
573
310
  significance_threshold:
574
311
  type: number
575
312
  minimum: 0.0001
@@ -594,7 +331,7 @@ UpdateExperimentRequest:
594
331
  items:
595
332
  $ref: ./common.yaml#/ExperimentInlineMetric
596
333
  additionalProperties: false
597
- description: Body for `PATCH /api/admin/experiments/{id}`. Partial — only supplied fields change. `allocation_pct`, `groups`, `salt`, `universe`, `params` are immutable while the experiment is running (stop first).
334
+ description: Body for `PATCH /api/admin/experiments/{id}`. Partial — only supplied fields change. `allocation_pct`, `salt`, `universe` and existing group weights/values are immutable while running (stop first); a new variant may still be appended into the reserved tail.
598
335
  UpdateExperimentResponse:
599
336
  type: object
600
337
  properties:
@@ -662,6 +399,12 @@ SetExperimentMetricsRequest:
662
399
  - guardrail
663
400
  - secondary
664
401
  description: Metric role. `goal` drives the decision, `guardrail` blocks ship if degraded, `secondary` is informational.
402
+ min_effect_of_interest:
403
+ description: Per-experiment override of the metric's `default_min_effect_of_interest` (relative, 0–1) — the smallest change worth acting on for THIS experiment's decision, which depends on the intervention's cost/risk. `null`/omitted falls back to the metric default. For a `guardrail` this is the non-inferiority margin (how large a regression is tolerated); for a `goal` it is the superiority threshold.
404
+ default: null
405
+ anyOf:
406
+ - type: number
407
+ - type: "null"
665
408
  required:
666
409
  - metric_id
667
410
  - role
@@ -689,9 +432,15 @@ SetExperimentMetricsResponse:
689
432
  - goal
690
433
  - guardrail
691
434
  - secondary
435
+ min_effect_of_interest:
436
+ description: The resolved per-experiment override, or `null` when this attachment inherits the metric's `default_min_effect_of_interest`.
437
+ anyOf:
438
+ - type: number
439
+ - type: "null"
692
440
  required:
693
441
  - metric_id
694
442
  - role
443
+ - min_effect_of_interest
695
444
  additionalProperties: false
696
445
  required:
697
446
  - id
@@ -755,6 +504,11 @@ GetExperimentResultsResponse:
755
504
  - type: number
756
505
  - type: "null"
757
506
  description: "`1` if sample-ratio mismatch detected, else `0`."
507
+ realized_mde:
508
+ anyOf:
509
+ - type: number
510
+ - type: "null"
511
+ description: "Realized minimum detectable effect (absolute, in metric units) — the smallest true effect this run could detect at the experiment's significance level and target power GIVEN the observed variance and per-arm sample sizes. A derived OUTPUT, not an input knob; compare it against the metric's minimum effect of interest to judge whether the run is adequately powered. `null` on the control row and on empty arms."
758
512
  required:
759
513
  - metric
760
514
  - group_name
@@ -764,6 +518,7 @@ GetExperimentResultsResponse:
764
518
  - delta_pct
765
519
  - p_value
766
520
  - srm_detected
521
+ - realized_mde
767
522
  additionalProperties: false
768
523
  verdict:
769
524
  type: string
@@ -25,13 +25,52 @@ GateTemplateRule:
25
25
  - exp_in
26
26
  description: "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. Semver order: `semver_gt`/`semver_gte`/`semver_lt`/`semver_lte`. String: `contains` (substring), `regex` (JS-flavour pattern). Cross-resource: `gate_pass` (value is another gate's name), `exp_in` (attr is an experiment name, value is a variant / `\"$holdout\"` / `\"$any\"`)."
27
27
  value:
28
- description: 'Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains/semver_*`; array of scalars for `in/not_in`; string pattern for `regex`; referenced gate name for `gate_pass`; variant selector for `exp_in`.'
28
+ description: 'Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains/semver_*`; array of scalars for `in/not_in`; string pattern for `regex`; referenced gate name for `gate_pass`; variant selector for `exp_in`. Required on every request rule (value-ops need it; the valueless built-in presets are read-only and never created via the API).'
29
+ anyOf:
30
+ - type: string
31
+ - type: number
32
+ - type: boolean
33
+ - type: array
34
+ items: {}
29
35
  required:
30
36
  - attr
31
37
  - op
32
38
  - value
33
39
  additionalProperties: false
34
40
  description: Single targeting predicate. Copy a template's rules, substitute the concrete `value`(s), and pass them as the `rules` arg of `release_flags_create`.
41
+ GateTemplateRuleResponse:
42
+ type: object
43
+ properties:
44
+ attr:
45
+ type: string
46
+ description: Attribute key on the evaluation context (e.g. `country`, `plan`, `email`). Matched case-sensitively against `Shipeasy.checkGate(user, name)` input. May be empty on a built-in template whose attribute is supplied at substitution time (e.g. the `exp_in` "in any experiment" preset — you fill in the experiment name).
47
+ op:
48
+ type: string
49
+ enum:
50
+ - eq
51
+ - neq
52
+ - in
53
+ - not_in
54
+ - gt
55
+ - gte
56
+ - lt
57
+ - lte
58
+ - contains
59
+ - regex
60
+ - semver_gt
61
+ - semver_gte
62
+ - semver_lt
63
+ - semver_lte
64
+ - gate_pass
65
+ - exp_in
66
+ description: "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. Semver order: `semver_gt`/`semver_gte`/`semver_lt`/`semver_lte`. String: `contains` (substring), `regex` (JS-flavour pattern). Cross-resource: `gate_pass` (value is another gate's name), `exp_in` (attr is an experiment name, value is a variant / `\"$holdout\"` / `\"$any\"`)."
67
+ value:
68
+ description: 'Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains/semver_*`; array of scalars for `in/not_in`; string pattern for `regex`; referenced gate name for `gate_pass`; variant selector for `exp_in`.'
69
+ required:
70
+ - attr
71
+ - op
72
+ additionalProperties: false
73
+ description: Single targeting predicate as returned by the API. `value` is optional here — read-only built-in templates (e.g. `@owner`, or presets whose operand is supplied at substitution time) legitimately omit it. Request bodies still require `value`.
35
74
  GateTemplate:
36
75
  type: object
37
76
  description: "A reusable targeting-rule template. Built-ins are read-only (`builtin: true`, stable slug `id`); per-project customer templates are `builtin: false` with a `gtpl_…` id."
@@ -65,7 +104,7 @@ GateTemplate:
65
104
  rules:
66
105
  type: array
67
106
  items:
68
- $ref: "#/GateTemplateRule"
107
+ $ref: "#/GateTemplateRuleResponse"
69
108
  description: The rule definition — copy, substitute the value(s), pass as `rules`.
70
109
  createdAt:
71
110
  anyOf:
@@ -21,6 +21,12 @@ ListGatesResponse:
21
21
  minimum: 0
22
22
  maximum: 1
23
23
  description: Master switch. Returned as `1`/`0` from D1; treat truthy as enabled.
24
+ type:
25
+ type: string
26
+ enum:
27
+ - targeting
28
+ - holdout
29
+ description: Gate kind — `targeting` (normal flag) or `holdout` (restricted public % + whitelist).
24
30
  rolloutPct:
25
31
  type: integer
26
32
  minimum: 0
@@ -301,6 +307,13 @@ CreateGateRequest:
301
307
  maxLength: 128
302
308
  pattern: ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$
303
309
  description: Stable gate key used by SDKs (`Shipeasy.checkGate(user, '<name>')`). Single segment or `folder.name`. Lowercase letters, digits, `_` or `-`; max 128 chars. Immutable after create — rename = delete + recreate.
310
+ type:
311
+ default: targeting
312
+ type: string
313
+ enum:
314
+ - targeting
315
+ - holdout
316
+ description: Gate kind. `targeting` (default) is a normal flag with the full builder. `holdout` is a **restricted** flag — only a public rollout % and a whitelist are allowed; attribute rules and a gatekeeper stack are rejected. Used as an experiment's `holdout_gate`.
304
317
  enabled:
305
318
  default: true
306
319
  description: Master switch. Defaults to `true`. Set `false` to create the gate disabled (evaluates to `false` regardless of rules/rollout); flip on via `POST /{id}/enable` or PATCH.
@@ -588,6 +601,12 @@ CreateGateResponse:
588
601
  UpdateGateRequest:
589
602
  type: object
590
603
  properties:
604
+ type:
605
+ type: string
606
+ enum:
607
+ - targeting
608
+ - holdout
609
+ description: Gate kind. Switching to `holdout` requires the gate carry only a public rollout % + whitelist (attribute rules / stack are rejected).
591
610
  rollout_pct:
592
611
  description: New rollout in **basis points** (0–10000 = 0%–100%) — `100` here means **1%**. Use `rollout_percent` (0–100) below for percent. Omit both to leave unchanged.
593
612
  type: integer
@@ -114,7 +114,8 @@ CreateKeyRequest:
114
114
  - events:write
115
115
  - configs:write
116
116
  - experiments:write
117
- description: Optional permission strings recorded on the key for audit/display.
117
+ - tickets:public_create
118
+ description: "Optional permission strings recorded on the key. `tickets:public_create` is enforced: a client key needs it (plus the project's `allowPublicTickets` setting) to file a `pending_approval` bug via the public `POST /cli/report` endpoint. The rest are audit/display only."
118
119
  expiresInDays:
119
120
  anyOf:
120
121
  - type: integer