|
1 .. _experiments_manifests: |
|
2 |
|
3 ===================== |
|
4 Experiments Manifests |
|
5 ===================== |
|
6 |
|
7 *Experiments Manifests* are documents that describe the set of active |
|
8 experiments a client may run. |
|
9 |
|
10 *Experiments Manifests* are fetched periodically by clients. When |
|
11 fetched, clients look at the experiments within the manifest and |
|
12 determine which experiments are applicable. If an experiment is |
|
13 applicable, the client may download and start the experiment. |
|
14 |
|
15 Manifest Format |
|
16 =============== |
|
17 |
|
18 Manifests are JSON documents where the main element is an object. |
|
19 |
|
20 The *schema* of the object is versioned and defined by the presence |
|
21 of a top-level ``version`` property, whose integer value is the |
|
22 schema version used by that manifest. Each version is documented |
|
23 in the sections below. |
|
24 |
|
25 Version 1 |
|
26 --------- |
|
27 |
|
28 Version 1 is the original manifest format. |
|
29 |
|
30 The following properties may exist in the root object: |
|
31 |
|
32 experiments |
|
33 An array of objects describing candidate experiments. The format of |
|
34 these objects is documented below. |
|
35 |
|
36 An array is used to create an explicit priority of experiments. |
|
37 Experiments listed at the beginning of the array take priority over |
|
38 experiments that follow. |
|
39 |
|
40 Experiments Objects |
|
41 ^^^^^^^^^^^^^^^^^^^ |
|
42 |
|
43 Each object in the ``experiments`` array may contain the following |
|
44 properties: |
|
45 |
|
46 id |
|
47 (required) String identifier of this experiment. The identifier should |
|
48 be treated as opaque by clients. It is used to uniquely identify an |
|
49 experiment for all of time. |
|
50 |
|
51 xpiURL |
|
52 (required) String URL of the XPI that implements this experiment. |
|
53 |
|
54 If the experiment is activated, the client will download and install this |
|
55 XPI. |
|
56 |
|
57 xpiHash |
|
58 (required) String hash of the XPI that implements this experiment. |
|
59 |
|
60 The value is composed of a hash identifier followed by a colon |
|
61 followed by the hash value. e.g. |
|
62 `sha1:f677428b9172e22e9911039aef03f3736e7f78a7`. `sha1` and `sha256` |
|
63 are the two supported hashing mechanisms. The hash value is the hex |
|
64 encoding of the binary hash. |
|
65 |
|
66 When the client downloads the XPI for the experiment, it should compare |
|
67 the hash of that XPI against this value. If the hashes don't match, |
|
68 the client should not install the XPI. |
|
69 |
|
70 Clients may also use this hash as a means of determining when an |
|
71 experiment's XPI has changed and should be refreshed. |
|
72 |
|
73 startTime |
|
74 Integer seconds since UNIX epoch that this experiment should |
|
75 start. Clients should not start an experiment if *now()* is less than |
|
76 this value. |
|
77 |
|
78 maxStartTime |
|
79 (optional) Integer seconds since UNIX epoch after which this experiment |
|
80 should no longer start. |
|
81 |
|
82 Some experiments may wish to impose hard deadlines after which no new |
|
83 clients should activate the experiment. This property may be used to |
|
84 facilitate that. |
|
85 |
|
86 endTime |
|
87 Integer seconds since UNIX epoch after which this experiment |
|
88 should no longer run. Clients should cease an experiment when the current |
|
89 time is beyond this value. |
|
90 |
|
91 maxActiveSeconds |
|
92 Integer seconds defining the max wall time this experiment should be |
|
93 active for. |
|
94 |
|
95 The client should deactivate the experiment this many seconds after |
|
96 initial activation. |
|
97 |
|
98 This value only involves wall time, not browser activity or session time. |
|
99 |
|
100 appName |
|
101 Array of application names this experiment should run on. |
|
102 |
|
103 An application name comes from ``nsIXULAppInfo.name``. It is a value |
|
104 like ``Firefox``, ``Fennec``, or `B2G`. |
|
105 |
|
106 The client should compare its application name against the members of |
|
107 this array. If a match is found, the experiment is applicable. |
|
108 |
|
109 minVersion |
|
110 (optional) String version number of the minimum application version this |
|
111 experiment should run on. |
|
112 |
|
113 A version number is something like ``27.0.0`` or ``28``. |
|
114 |
|
115 The client should compare its version number to this value. If the client's |
|
116 version is greater or equal to this version (using a version-aware comparison |
|
117 function), the experiment is applicable. |
|
118 |
|
119 If this is not specified, there is no lower bound to versions this |
|
120 experiment should run on. |
|
121 |
|
122 maxVersion |
|
123 (optional) String version number of the maximum application version this |
|
124 experiment should run on. |
|
125 |
|
126 This is similar to ``minVersion`` except it sets the upper bound for |
|
127 application versions. |
|
128 |
|
129 If the client's version is less than or equal to this version, the |
|
130 experiment is applicable. |
|
131 |
|
132 If this is not specified, there is no upper bound to versions this |
|
133 experiment should run on. |
|
134 |
|
135 version |
|
136 (optional) Array of application versions this experiment should run on. |
|
137 |
|
138 This is similar to ``minVersion`` and ``maxVersion`` except only a |
|
139 whitelisted set of specific versions are allowed. |
|
140 |
|
141 The client should compare its version to members of this array. If a match |
|
142 is found, the experiment is applicable. |
|
143 |
|
144 minBuildID |
|
145 (optional) String minimum Build ID this experiment should run on. |
|
146 |
|
147 Build IDs are values like ``201402261424``. |
|
148 |
|
149 The client should perform a string comparison of its Build ID against this |
|
150 value. If its value is greater than or equal to this value, the experiment |
|
151 is applicable. |
|
152 |
|
153 maxBuildID |
|
154 (optional) String maximum Build ID this experiment should run on. |
|
155 |
|
156 This is similar to ``minBuildID`` except it sets the upper bound |
|
157 for Build IDs. |
|
158 |
|
159 The client should perform a string comparison of its Build ID against |
|
160 this value. If its value is less than or equal to this value, the |
|
161 experiment is applicable. |
|
162 |
|
163 buildIDs |
|
164 (optional) Array of Build IDs this experiment should run on. |
|
165 |
|
166 This is similar to ``minBuildID`` and ``maxBuildID`` except only a |
|
167 whitelisted set of Build IDs are considered. |
|
168 |
|
169 The client should compare its Build ID to members of this array. If a |
|
170 match is found, the experiment is applicable. |
|
171 |
|
172 os |
|
173 (optional) Array of operating system identifiers this experiment should |
|
174 run on. |
|
175 |
|
176 Values for this array come from ``nsIXULRuntime.OS``. |
|
177 |
|
178 The client will compare its operating system identifier to members |
|
179 of this array. If a match is found, the experiment is applicable to the |
|
180 client. |
|
181 |
|
182 channel |
|
183 (optional) Array of release channel identifiers this experiment should run |
|
184 on. |
|
185 |
|
186 The client will compare its channel to members of this array. If a match |
|
187 is found, the experiment is applicable. |
|
188 |
|
189 If this property is not defined, the client should assume the experiment |
|
190 is to run on all channels. |
|
191 |
|
192 locale |
|
193 (optional) Array of locale identifiers this experiment should run on. |
|
194 |
|
195 A locale identifier is a string like ``en-US`` or ``zh-CN`` and is |
|
196 obtained by looking at |
|
197 ``nsIXULChromeRegistry.getSelectedLocale("global")``. |
|
198 |
|
199 The client should compare its locale identifier to members of this array. |
|
200 If a match is found, the experiment is applicable. |
|
201 |
|
202 If this property is not defined, the client should assume the experiment |
|
203 is to run on all locales. |
|
204 |
|
205 sample |
|
206 (optional) Decimal number indicating the sampling rate for this experiment. |
|
207 |
|
208 This will contain a value between ``0.0`` and ``1.0``. The client should |
|
209 generate a random decimal between ``0.0`` and ``1.0``. If the randomly |
|
210 generated number is less than or equal to the value of this field, the |
|
211 experiment is applicable. |
|
212 |
|
213 disabled |
|
214 (optional) Boolean value indicating whether an experiment is disabled. |
|
215 |
|
216 Normally, experiments are deactivated after a certain time has passed or |
|
217 after the experiment itself determines it no longer needs to run (perhaps |
|
218 it collected sufficient data already). |
|
219 |
|
220 This property serves as a backup mechanism to remotely disable an |
|
221 experiment before it was scheduled to be disabled. It can be used to |
|
222 kill experiments that are found to be doing wrong or bad things or that |
|
223 aren't useful. |
|
224 |
|
225 If this property is not defined or is false, the client should assume |
|
226 the experiment is active and a candidate for activation. |
|
227 |
|
228 frozen |
|
229 (optional) Boolean value indicating this experiment is frozen and no |
|
230 longer accepting new enrollments. |
|
231 |
|
232 If a client sees a true value in this field, it should not attempt to |
|
233 activate an experiment. |
|
234 |
|
235 jsfilter |
|
236 (optional) JavaScript code that will be evaluated to determine experiment |
|
237 applicability. |
|
238 |
|
239 This property contains the string representation of JavaScript code that |
|
240 will be evaluated in a sandboxed environment using JavaScript's |
|
241 ``eval()``. |
|
242 |
|
243 The string is expected to contain the definition of a JavaScript function |
|
244 ``filter(context)``. This function receives as its argument an object |
|
245 holding application state. See the section below for the definition of |
|
246 this object. |
|
247 |
|
248 The purpose of this property is to allow experiments to define complex |
|
249 rules and logic for evaluating experiment applicability in a manner |
|
250 that is privacy conscious and doesn't require the transmission of |
|
251 excessive data. |
|
252 |
|
253 The return value of this filter indicates whether the experiment is |
|
254 applicable. Functions should return true if the experiment is |
|
255 applicable. |
|
256 |
|
257 If an experiment is not applicable, they should throw an Error whose |
|
258 message contains the reason the experiment is not applicable. This |
|
259 message may be logged and sent to remote servers, so it should not |
|
260 contain private or otherwise sensitive data that wouldn't normally |
|
261 be submitted. |
|
262 |
|
263 If a falsey (or undefined) value is returned, the client should |
|
264 assume the experiment is not applicable. |
|
265 |
|
266 If this property is not defined, the client does not consider a custom |
|
267 JavaScript filter function when determining whether an experiment is |
|
268 applicable. |
|
269 |
|
270 JavaScript Filter Context Objects |
|
271 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
272 |
|
273 The object passed to a ``jsfilter`` ``filter()`` function contains the |
|
274 following properties: |
|
275 |
|
276 healthReportSubmissionEnabled |
|
277 This property contains a boolean indicating whether Firefox Health |
|
278 Report has its data submission flag enabled (whether Firefox Health |
|
279 Report is sending data to remote servers). |
|
280 |
|
281 healthReportPayload |
|
282 This property contains the current Firefox Health Report payload. |
|
283 |
|
284 The payload format is documented at :ref:`healthreport_dataformat`. |
|
285 |
|
286 telemetryPayload |
|
287 This property contains the current Telemetry payload. |
|
288 |
|
289 The evaluation sandbox for the JavaScript filters may be destroyed |
|
290 immediately after ``filter()`` returns. This function should not assume |
|
291 async code will finish. |
|
292 |
|
293 Experiment Applicability and Client Behavior |
|
294 ============================================ |
|
295 |
|
296 The point of an experiment manifest is to define which experiments are |
|
297 available and where and how to run them. This section explains those |
|
298 rules in more detail. |
|
299 |
|
300 Many of the properties in *Experiment Objects* are related to determining |
|
301 whether an experiment should run on a given client. This evaluation is |
|
302 performed client side. |
|
303 |
|
304 1. Multiple conditions in an experiment |
|
305 --------------------------------------- |
|
306 |
|
307 If multiple conditions are defined for an experiment, the client should |
|
308 combine each condition with a logical *AND*: all conditions must be |
|
309 satisfied for an experiment to run. If one condition fails, the experiment |
|
310 is not applicable. |
|
311 |
|
312 2. Active experiment disappears from manifest |
|
313 --------------------------------------------- |
|
314 |
|
315 If a specific experiment disappears from the manifest, the client should |
|
316 continue conducting an already-active experiment. Furthermore, the |
|
317 client should remember what the expiration events were for an experiment |
|
318 and honor them. |
|
319 |
|
320 The rationale here is that we want to prevent an accidental deletion |
|
321 or temporary failure on the server to inadvertantly deactivate |
|
322 supposed-to-be-active experiments. We also don't want premature deletion |
|
323 of an experiment from the manifest to result in indefinite activation |
|
324 periods. |
|
325 |
|
326 3. Inactive experiment disappears from manifest |
|
327 ----------------------------------------------- |
|
328 |
|
329 If an inactive but scheduled-to-be-active experiment disappears from the |
|
330 manifest, the client should not activate the experiment. |
|
331 |
|
332 If that experiment reappears in the manifest, the client should not |
|
333 treat that experiment any differently than any other new experiment. Put |
|
334 another way, the fact an inactive experiment disappears and then |
|
335 reappears should not be significant. |
|
336 |
|
337 The rationale here is that server operators should have complete |
|
338 control of an inactive experiment up to it's go-live date. |
|
339 |
|
340 4. Re-evaluating applicability on manifest refresh |
|
341 -------------------------------------------------- |
|
342 |
|
343 When an experiment manifest is refreshed or updated, the client should |
|
344 re-evaluate the applicability of each experiment therein. |
|
345 |
|
346 The rationale here is that the server may change the parameters of an |
|
347 experiment and want clients to pick those up. |
|
348 |
|
349 5. Activating a previously non-applicable experiment |
|
350 ---------------------------------------------------- |
|
351 |
|
352 If the conditions of an experiment change or the state of the client |
|
353 changes to allow an experiment to transition from previously |
|
354 non-applicable to applicable, the experiment should be activated. |
|
355 |
|
356 For example, if a client is running version 28 and the experiment |
|
357 initially requires version 29 or above, the client will not mark the |
|
358 experiment as applicable. But if the client upgrades to version 29 or if |
|
359 the manifest is updated to require 28 or above, the experiment will |
|
360 become applicable. |
|
361 |
|
362 6. Deactivating a previously active experiment |
|
363 ---------------------------------------------- |
|
364 |
|
365 If the conditions of an experiment change or the state of the client |
|
366 changes and an active experiment is no longer applicable, that |
|
367 experiment should be deactivated. |
|
368 |
|
369 7. Calculation of sampling-based applicability |
|
370 ---------------------------------------------- |
|
371 |
|
372 For calculating sampling-based applicability, the client will associate |
|
373 a random value between ``0.0`` and ``1.0`` for each observed experiment |
|
374 ID. This random value will be generated the first time sampling |
|
375 applicability is evaluated. This random value will be persisted and used |
|
376 in future applicability evaluations for this experiment. |
|
377 |
|
378 By saving and re-using the value, the client is able to reliably and |
|
379 consistently evaluate applicability, even if the sampling threshold |
|
380 in the manifest changes. |
|
381 |
|
382 Clients should retain the randomly-generated sampling value for |
|
383 experiments that no longer appear in a manifest for a period of at least |
|
384 30 days. The rationale is that if an experiment disappears and reappears |
|
385 from a manifest, the client will not have multiple opportunities to |
|
386 generate a random value that satisfies the sampling criteria. |
|
387 |
|
388 8. Incompatible version numbers |
|
389 ------------------------------- |
|
390 |
|
391 If a client receives a manifest with a version number that it doesn't |
|
392 recognize, it should ignore the manifest. |
|
393 |
|
394 9. Usage of old manifests |
|
395 ------------------------- |
|
396 |
|
397 If a client experiences an error fetching a manifest (server not |
|
398 available) or if the manifest is corrupt, not readable, or compatible, |
|
399 the client may use a previously-fetched (cached) manifest. |
|
400 |
|
401 10. Updating XPIs |
|
402 ----------------- |
|
403 |
|
404 If the URL or hash of an active experiment's XPI changes, the client |
|
405 should fetch the new XPI, uninstall the old XPI, and install the new |
|
406 XPI. |
|
407 |
|
408 Examples |
|
409 ======== |
|
410 |
|
411 Here is an example manifest:: |
|
412 |
|
413 { |
|
414 "version": 1, |
|
415 "experiments": [ |
|
416 { |
|
417 "id": "da9d7f4f-f3f9-4f81-bacd-6f0626ffa360", |
|
418 "xpiURL": "https://experiments.mozilla.org/foo.xpi", |
|
419 "xpiHash": "sha1:cb1eb32b89d86d78b7326f416cf404548c5e0099", |
|
420 "startTime": 1393000000, |
|
421 "endTime": 1394000000, |
|
422 "appName": ["Firefox", "Fennec"], |
|
423 "minVersion": "28", |
|
424 "maxVersion": "30", |
|
425 "os": ["windows", "linux", "osx"], |
|
426 "jsfilter": "function filter(context) { return context.healthReportEnabled; }" |
|
427 } |
|
428 ] |
|
429 } |