@thinkingai/ae-cli 6.1.17 → 6.1.19

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 (126) hide show
  1. package/README.md +2 -0
  2. package/README.zh.md +6 -0
  3. package/dist/{auth-77BUFLGC.js → auth-QPEVVBKT.js} +20 -15
  4. package/dist/auth-UMJAA72O.js +15 -0
  5. package/dist/{capability-72DTW5M2.js → capability-ASI62I4A.js} +53 -15
  6. package/dist/{chunk-UW5UN47B.js → chunk-533JK3YX.js} +2 -0
  7. package/dist/{chunk-UOUS37JQ.js → chunk-6QK7SYYY.js} +5 -4
  8. package/dist/{chunk-TUKQZTMI.js → chunk-7K24F7T2.js} +2 -0
  9. package/dist/{chunk-OO6XR6LK.js → chunk-AMBFK2K3.js} +2 -0
  10. package/dist/{sync-DAVKYVMW.js → chunk-B5HMQAOM.js} +31 -540
  11. package/dist/{chunk-VR3LCBHW.js → chunk-DKEXH6Q5.js} +6 -5
  12. package/dist/{chunk-VTWMIC5L.js → chunk-E2JKXMVO.js} +2 -0
  13. package/dist/{chunk-LYVNONC4.js → chunk-FR2EDAQM.js} +36 -0
  14. package/dist/{chunk-ILIU36SU.js → chunk-GJXRF7Y6.js} +6 -5
  15. package/dist/{chunk-DWO43OIB.js → chunk-JQ3ENZZH.js} +2 -0
  16. package/dist/chunk-JYMGHGCE.js +191 -0
  17. package/dist/{chunk-GT46FPXN.js → chunk-KEWVSO64.js} +18 -8
  18. package/dist/chunk-KZ6ZHF5J.js +294 -0
  19. package/dist/chunk-O6K2ODUE.js +318 -0
  20. package/dist/chunk-QL6R6TSK.js +25215 -0
  21. package/dist/{chunk-4SGZG4XY.js → chunk-RWXIXOZG.js} +28 -13
  22. package/dist/{chunk-YA6SMTXG.js → chunk-S5PONFBM.js} +5 -4
  23. package/dist/{chunk-4NN5IWVN.js → chunk-T6OSFQZD.js} +2 -0
  24. package/dist/{chunk-PTE56QPL.js → chunk-TKHSULJT.js} +6 -0
  25. package/dist/{chunk-6EIJSNBD.js → chunk-Y74WTIKJ.js} +2 -0
  26. package/dist/{client-TKG4WBHN.js → client-N7NGZUNI.js} +6 -4
  27. package/dist/{community-report-client-FI4LNVYS.js → community-report-client-6OL6GBQW.js} +3 -3
  28. package/dist/{config-RE6CMGPK.js → config-XNMACCKX.js} +10 -8
  29. package/dist/{data-integration-XQYB4X4F.js → data-integration-4NZGZ45E.js} +2502 -272
  30. package/dist/index.js +137 -1245
  31. package/dist/{local-data-upload-client-BWHSUQQK.js → local-data-upload-client-EFHDLXFG.js} +3 -3
  32. package/dist/{memory-YK33G4T7.js → memory-HBJQ2GC5.js} +8 -7
  33. package/dist/{metadata-UILXHBWF.js → metadata-62EWBEIG.js} +12 -11
  34. package/dist/{model-NR3JHFSJ.js → model-BHLJ2QMT.js} +10 -9
  35. package/dist/personal-semantic-preference-JBVMAI7L.js +240 -0
  36. package/dist/project-semantic-BQ4MPUS5.js +1115 -0
  37. package/dist/sync-MUWPRM5I.js +522 -0
  38. package/dist/{te-agent-4BKBODMF.js → te-agent-WQZTMEK4.js} +12 -10
  39. package/dist/{te-analysis-O6DCO6BS.js → te-analysis-MNCG65LU.js} +534 -48
  40. package/dist/{te-community-HLC43QKH.js → te-community-BNE6KREL.js} +8 -7
  41. package/dist/{te-dataops-EJP56W3K.js → te-dataops-TXLKM2W6.js} +469 -68
  42. package/dist/{te-engage-FGBGQ4IY.js → te-engage-TPKLRVTL.js} +84 -10
  43. package/dist/{te-experiment-SO5MPDMJ.js → te-experiment-6BYKTCY7.js} +303 -12
  44. package/dist/{te-kb-SQCLHG6X.js → te-kb-BUD6N3NI.js} +312 -25
  45. package/dist/{te-system-YARIK4S5.js → te-system-44LZJDTQ.js} +573 -37
  46. package/dist/{te-team-EFKWYKMK.js → te-team-XMP47YXE.js} +10 -7
  47. package/dist/{update-OGPSZM5A.js → update-UODFOZ4P.js} +9 -7
  48. package/package.json +18 -9
  49. package/skills/ae-agent/SKILL.md +3 -4
  50. package/skills/ae-agent/references/edit-skill.md +3 -0
  51. package/skills/ae-agent/references/get-skill-content.md +1 -1
  52. package/skills/ae-agent/references/rescan-skills.md +15 -13
  53. package/skills/ae-agent/references/upload-skill.md +7 -4
  54. package/skills/ae-analysis/SKILL.md +45 -4
  55. package/skills/ae-analysis/metadata_resolution.md +38 -4
  56. package/skills/ae-analysis/references/analysis_data_retrieval.md +29 -0
  57. package/skills/ae-analysis/references/analysis_gateway_assets.md +1 -1
  58. package/skills/ae-analysis/references/asset_authentication_export.md +22 -0
  59. package/skills/ae-analysis/references/asset_authentication_list.md +18 -14
  60. package/skills/ae-analysis/references/asset_authentication_update.md +29 -14
  61. package/skills/ae-analysis/references/audience_models.md +18 -0
  62. package/skills/ae-analysis/references/command_index.md +19 -11
  63. package/skills/ae-analysis/references/dashboard_get.md +18 -1
  64. package/skills/ae-analysis/references/dashboard_update.md +3 -0
  65. package/skills/ae-analysis/references/personal_semantic_preference_add.md +23 -0
  66. package/skills/ae-analysis/references/personal_semantic_preference_delete.md +17 -0
  67. package/skills/ae-analysis/references/personal_semantic_preference_get.md +19 -0
  68. package/skills/ae-analysis/references/personal_semantic_preference_list.md +21 -0
  69. package/skills/ae-analysis/references/personal_semantic_preference_update.md +19 -0
  70. package/skills/ae-analysis/references/project_timezone_update.md +13 -4
  71. package/skills/ae-analysis/references/property_create.md +2 -0
  72. package/skills/ae-analysis/references/super_metadata_batch_create.md +2 -0
  73. package/skills/ae-analysis/references/user_cluster_models.md +2 -0
  74. package/skills/ae-analysis/references/user_cluster_update.md +8 -4
  75. package/skills/ae-analysis/references/user_tag_create.md +7 -1
  76. package/skills/ae-analysis/references/user_tag_models.md +8 -2
  77. package/skills/ae-data-integration/SKILL.md +24 -4
  78. package/skills/ae-data-integration/references/custom-layer.md +93 -0
  79. package/skills/ae-data-integration/references/error-handling.md +145 -0
  80. package/skills/ae-data-integration/references/handoff.md +77 -18
  81. package/skills/ae-data-integration/references/local-analysis.md +1 -1
  82. package/skills/ae-data-integration/references/reuse.md +9 -5
  83. package/skills/ae-data-integration/references/sink-upload.md +1 -1
  84. package/skills/ae-data-integration/references/source-inspect.md +35 -13
  85. package/skills/ae-data-integration/references/tracking-plan.md +7 -5
  86. package/skills/ae-data-integration/references/transform.md +12 -10
  87. package/skills/ae-data-integration/references/ue-mapping.md +33 -11
  88. package/skills/ae-data-integration/references/ue-routing.md +23 -0
  89. package/skills/ae-dataops/SKILL.md +11 -1
  90. package/skills/ae-dataops/references/dataops-backfill.md +135 -0
  91. package/skills/ae-engage/SKILL.md +5 -0
  92. package/skills/ae-engage/references/build-task-save-guide.md +14 -1
  93. package/skills/ae-engage/references/save-flow.md +37 -1
  94. package/skills/ae-engage/references/save-task.md +88 -0
  95. package/skills/ae-experiment/SKILL.md +14 -4
  96. package/skills/ae-experiment/references/manage_feature_whitelist.md +66 -0
  97. package/skills/ae-experiment/references/manage_guardrail_metrics.md +26 -0
  98. package/skills/ae-experiment/references/save_experiment.md +1 -1
  99. package/skills/ae-experiment/references/save_metric.md +20 -8
  100. package/skills/ae-kb/SKILL.md +121 -10
  101. package/skills/ae-project-semantic/SKILL.md +193 -0
  102. package/skills/ae-project-semantic/references/query-routing-v5.md +165 -0
  103. package/skills/ae-project-semantic/references/recommendation-quality.md +68 -0
  104. package/skills/ae-system/SKILL.md +28 -30
  105. package/skills/ae-system/references/channel-management.md +303 -0
  106. package/dist/auth-2WTQOP77.js +0 -14
  107. package/dist/capability-PJHNI4GJ.js +0 -315
  108. package/dist/chunk-4KVPKXFX.js +0 -98
  109. package/dist/chunk-C4MGVGJW.js +0 -13
  110. package/dist/chunk-P3FGXJTU.js +0 -349
  111. package/dist/chunk-QGM4M3NI.js +0 -37
  112. package/dist/chunk-RGKJGKT7.js +0 -71
  113. package/dist/chunk-SAU3QFIQ.js +0 -556
  114. package/dist/chunk-VPKZ7I72.js +0 -509
  115. package/dist/chunk-ZZUOD757.js +0 -598
  116. package/dist/memory-CHRU2F7W.js +0 -893
  117. package/dist/metadata-XXR34N5P.js +0 -339
  118. package/dist/model-K3KLWIW6.js +0 -139
  119. package/dist/sync-FCKOVWWS.js +0 -10261
  120. package/dist/te-agent-HLW4VTQK.js +0 -3893
  121. package/dist/te-analysis-ZMNGOVNW.js +0 -8958
  122. package/dist/te-community-6HPBWJUZ.js +0 -1859
  123. package/dist/te-dataops-HDRUXY4K.js +0 -2208
  124. package/dist/te-engage-RAK5PESW.js +0 -4898
  125. package/dist/te-experiment-VZF7BT6G.js +0 -770
  126. package/dist/te-system-Z77IKZFN.js +0 -2213
@@ -36,12 +36,16 @@ compounds when reusing `definition_request`; flattening them changes audience se
36
36
  For the second sequence step, omit `relative_to_first` or set it to `false`; use `true` only
37
37
  from the third step onward when its window must be measured from step 1.
38
38
 
39
- For existing-cluster audiences (`targetClusterType=2`), you may copy server-authored definitions via:
39
+ For server-side existing-cluster audiences (`targetClusterType=2`), you may copy server-authored definitions via:
40
40
 
41
41
  ```bash
42
42
  ae-cli analysis user-cluster get --project-id <projectId> --cluster-names '["<cluster_name>"]'
43
43
  ```
44
44
 
45
+ Server-side channels allow custom (`1`) or existing (`2`) audiences and reject all users (`3`).
46
+ `client_push` (`channelType=3`) allows custom (`1`) or all users (`3`) and rejects existing (`2`).
47
+ Always pass `channelType` in `context` so the guide can validate this matrix.
48
+
45
49
  4. Build the final grouped `save_task.req`.
46
50
  5. Submit with `ae-cli engage-task task save --project-id <projectId> --req '{...}'`.
47
51
 
@@ -229,6 +233,8 @@ When experiment mode is enabled (`context.enableExp=true` or draft `expConfig.en
229
233
  - capability `engage-task.task.build-save-guide` enriches `handoff.reqTemplate.channelConfig.groupContentList`
230
234
  so each entry carries `expGroupName`, `expGroupType`, `percentageInExperiment`, `order`, and `contentList`
231
235
  - do not drop those association fields when filling content; they must stay aligned with `expConfig.expGroupList`
236
+ - copy the complete group tuple (`expGroupName`, `expGroupType`, `percentageInExperiment`, `order`)
237
+ into both lists; matching only by list position is not sufficient
232
238
 
233
239
  ### 4.8 `fieldRules`
234
240
 
@@ -300,6 +306,11 @@ Apply this rule only to
300
306
  `completionIndicatorDef.completionIndicators[].eventDefinition.filters`. Trigger-event filters have
301
307
  their own scenario rules and are not subject to this completion-filter restriction.
302
308
 
309
+ For `completionIndicatorType=0`, also read and preserve `requiredMainGoalFields` and
310
+ `touchCycleRule`. A valid main goal includes `touch_cycle_num` and `touch_cycle_num_unit`; use `1`
311
+ and `day` when no custom completion window is requested. Do not rely on static `--validate` alone
312
+ because the save service performs this additional business validation.
313
+
303
314
  ### 4.9 `handoff`
304
315
 
305
316
  This is the final section before `save_task`.
@@ -336,6 +347,8 @@ Recommended usage pattern:
336
347
  definition directly
337
348
  7. omit `clientConfig.clientQp`; partial updates preserve the server-authored value
338
349
  8. call `engage-task task save`
350
+ 9. after an experiment save succeeds, call `engage-task task get` and verify that both
351
+ `exp_config.exp_group_list` and `group_content_list` contain the expected group tuples
339
352
 
340
353
  ---
341
354
 
@@ -305,9 +305,45 @@ Fallback branch keeps only `branchId` + `branchType: 2`.
305
305
  #### `ab_split_flow`
306
306
 
307
307
  ```json
308
- { "branchList": [ { "branchId": "<branchId>", "branchName": "Control Group", "branchType": 1, "order": 1, "percentageInExperiment": 34 }, { "branchId": "<branchId>", "branchName": "Experiment Group A", "branchType": 2, "order": 2, "percentageInExperiment": 33 } ], "indicatorsDef": [], "activateIndicatorsDef": null }
308
+ {
309
+ "branchList": [
310
+ { "branchId": "control", "branchName": "Control Group", "branchType": 1, "order": 1, "percentageInExperiment": 50 },
311
+ { "branchId": "experiment_a", "branchName": "Experiment Group A", "branchType": 2, "order": 2, "percentageInExperiment": 50 }
312
+ ],
313
+ "indicatorsDef": [
314
+ {
315
+ "indicatorsUuid": "metric_1",
316
+ "name": "Maximum payment amount",
317
+ "desc": "",
318
+ "completionIndicatorType": 0,
319
+ "touch_cycle_num": 1,
320
+ "touch_cycle_num_unit": "day",
321
+ "eventDefinition": {
322
+ "type": "event",
323
+ "event": "payment",
324
+ "aggregation": "max",
325
+ "property": "pay_amount",
326
+ "operator": "gt",
327
+ "value": 0,
328
+ "filters": {
329
+ "relation": "and",
330
+ "items": [
331
+ { "field": "gold", "operator": "gt", "values": [20] }
332
+ ]
333
+ }
334
+ }
335
+ }
336
+ ],
337
+ "activateIndicatorsDef": null
338
+ }
309
339
  ```
310
340
 
341
+ Use `eventDefinition` for new Capability requests. Its top-level `operator` compares the aggregate
342
+ result with `value`; each `filters.items[].operator` compares an event property with its `values`.
343
+ Both comparison levels are explicit and must not be omitted. Do not construct persisted fields such
344
+ as `event`, `taPropQuota`, `uceCalcuSymbol`, `num`, `filts`, or `calcuSymbol`; Hermes compiles them.
345
+ Legacy `event` remains accepted temporarily for older clients, but never send both fields.
346
+
311
347
  #### `event_judge`
312
348
 
313
349
  ```json
@@ -245,6 +245,12 @@ Use the guide to decide which audience shape applies:
245
245
  - `targetClusterType=2`: existing cluster, requires `clusterKey`
246
246
  - `targetClusterType=3`: all users, forbids `definitionRequest` and `clusterKey`
247
247
 
248
+ Audience availability depends on delivery side:
249
+
250
+ - Server-side channels support `targetClusterType=1` (custom) and `2` (existing), but not `3` (all users).
251
+ - `client_push` (`channelType=3`) supports `targetClusterType=1` (custom) and `3` (all users), but not `2` (existing).
252
+ - Determine the delivery side from the selected real channel; do not infer audience support from `triggerType` alone.
253
+
248
254
  For a custom audience, pass the semantic definition directly. Do not create an intermediate
249
255
  cluster or copy persisted QP.
250
256
 
@@ -426,6 +432,11 @@ When the guide points to event-based completion or experiment-driven main-goal r
426
432
  Read `fieldRules.blocks.controlConfig.completionIndicatorDef.filterPropertySelectTypes` and exclude
427
433
  every property type listed under `excluded` before constructing its `filters`.
428
434
 
435
+ For a main goal (`completionIndicatorType=0`), always include `touch_cycle_num` and
436
+ `touch_cycle_num_unit`. If the user does not request another completion window, use
437
+ `touch_cycle_num=1` and `touch_cycle_num_unit="day"`. Static Capability validation may accept a
438
+ main goal without these fields, but the Hermes save service rejects it.
439
+
429
440
  Important constraints that still apply:
430
441
 
431
442
  - `doNotDisturb.enableDoNotDisturb=true` requires `startTime` and `endTime` in `HH:mm`
@@ -444,6 +455,81 @@ compatibility field, and partial task updates preserve the existing server value
444
455
  client-side condition has no semantic field in the current contract, stop and report that it cannot
445
456
  be safely authored through this Capability.
446
457
 
458
+ ### 4.7 Verified A/B Task Template
459
+
460
+ Use this shape as the starting point for a server-channel split experiment. Replace every
461
+ placeholder with metadata discovered from the current project.
462
+
463
+ ```json
464
+ {
465
+ "baseInfo": {
466
+ "taskName": "<taskName>",
467
+ "taskDesc": "<taskDescription>",
468
+ "tzOffset": "<projectTimezoneOrDefaultSentinel>"
469
+ },
470
+ "channelConfig": {
471
+ "channelType": 1,
472
+ "channelId": "<verifiedChannelId>",
473
+ "groupContentList": [
474
+ {
475
+ "expGroupName": "Control",
476
+ "expGroupType": 1,
477
+ "percentageInExperiment": 50,
478
+ "order": 0,
479
+ "contentList": [{ "pushLanguageCode": "default", "content": "<channelContentJsonString>" }]
480
+ },
481
+ {
482
+ "expGroupName": "Experiment A",
483
+ "expGroupType": 2,
484
+ "percentageInExperiment": 50,
485
+ "order": 1,
486
+ "contentList": [{ "pushLanguageCode": "default", "content": "<channelContentJsonString>" }]
487
+ }
488
+ ]
489
+ },
490
+ "targetConfig": {
491
+ "targetClusterType": 1,
492
+ "definitionRequest": "<semanticAudienceDefinition>"
493
+ },
494
+ "triggerConfig": { "triggerType": 2 },
495
+ "controlConfig": {
496
+ "completionIndicatorDef": {
497
+ "completionIndicators": [
498
+ {
499
+ "completionIndicatorType": 0,
500
+ "touch_cycle_num": 1,
501
+ "touch_cycle_num_unit": "day",
502
+ "eventDefinition": {
503
+ "type": "event",
504
+ "event": "<verifiedGoalEvent>",
505
+ "aggregation": "count",
506
+ "operator": "gte",
507
+ "value": 1
508
+ }
509
+ }
510
+ ]
511
+ },
512
+ "frequencyLimits": { "enableFrequencyLimits": false, "ruleList": [] }
513
+ },
514
+ "expConfig": {
515
+ "enableExp": true,
516
+ "expType": 1,
517
+ "percentageInLayer": 100,
518
+ "expIndicatorBizType": 1,
519
+ "controlGroupSkipPush": false,
520
+ "expGroupList": [
521
+ { "expGroupName": "Control", "expGroupType": 1, "percentageInExperiment": 50, "order": 0 },
522
+ { "expGroupName": "Experiment A", "expGroupType": 2, "percentageInExperiment": 50, "order": 1 }
523
+ ]
524
+ }
525
+ }
526
+ ```
527
+
528
+ The experiment group tuple (`expGroupName`, `expGroupType`, `percentageInExperiment`, `order`)
529
+ must be identical between each `expConfig.expGroupList` entry and its corresponding
530
+ `channelConfig.groupContentList` entry. Validate the final request, save it, then call `task get`
531
+ and verify both persisted lists; a successful task ID alone is not sufficient verification.
532
+
447
533
  ---
448
534
 
449
535
  ## 5. Final Self-Check Before `engage-task task save`
@@ -461,6 +547,8 @@ Before submission, verify:
461
547
  9. No unsupported `triggerType=6` is used.
462
548
  10. Ordered steps contain `eventDefinition` and sequence metadata, not persisted aggregate fields.
463
549
  11. No placeholder IDs or fabricated resource names remain in the request.
550
+ 12. Every main goal includes `touch_cycle_num` and `touch_cycle_num_unit`.
551
+ 13. For experiments, `expGroupList` and `groupContentList` contain identical group tuples.
464
552
 
465
553
  ---
466
554
 
@@ -33,10 +33,14 @@ Naming and response boundary:
33
33
  `targeting.definition_request`. Never generate or submit `targetConfig`.
34
34
  - Metric QP is semantic at the CLI boundary: write `metricDefinition`; read
35
35
  `metric_definition`. Never generate or submit `metricConfig`, `calcType`, or `Axxx` codes.
36
+ - Event-property comparisons belong in `metricDefinition.filters`, using
37
+ `{relation,items:[{field,operator,values}]}`. Never put comparison fields directly on
38
+ `metricDefinition`, and never submit raw `filts`, `calcuSymbol`, or `ftv` fields.
36
39
  - For metric aggregations `sum` / `avg` / `max` / `distinct_count`, `metricDefinition.property`
37
40
  is **required** and must be a concrete available event property from Analysis metadata.
38
41
  Never create property aggregations without `property` (for example `metric_avg_no_property_*`).
39
- - Event-count aggregations `total_count` / `user_count` / `active_days` omit `property`.
42
+ - Preset event aggregations `total_count` / `user_count` / `active_days` omit `property`.
43
+ - Experiment metric creation does not support `avg_per_user` / `A105`.
40
44
  - Resolve event and property names with Analysis metadata before saving semantic definitions.
41
45
  - Lists return `data.items` and `data.total`; detail commands return `data.item`.
42
46
  - Readiness returns `data.readiness`; reports return `data.report`; save guides return `data.guide`; save dry-run validation returns `data.validation`; writes return `data.result`.
@@ -56,6 +60,7 @@ Naming and response boundary:
56
60
  - `experiment feature save`
57
61
  - `experiment metric save`
58
62
  3. Create or patch the experiment draft with `experiment experiment save`.
63
+ Use `experiment experiment update-metrics` when replacing metric bindings or assigning guardrail roles.
59
64
  4. Check readiness with `experiment experiment ready-check`.
60
65
  5. For a non-mutex traffic layer, run `experiment experiment conflict-check` before submit (needs `feature_key_list` from context or `experiment get`).
61
66
  6. Move status with `experiment experiment manage`.
@@ -66,11 +71,12 @@ If an experiment save returns `error_code: METRIC_NOT_FOUND`, list metrics for t
66
71
  ## Parameter Conventions
67
72
 
68
73
  - Experiment save payloads distinguish two allocation fields: experiment-level `req.allocation` (**integer only; no decimals**) and group-level `req.groups[].allocation` (**integer only; sum must equal `100` exactly**).
74
+ - Public experiment metric roles are `primary`, `secondary`, and `guardrail`. The internal `observation` role is currently unavailable for saves. Guardrail is a binding role; updating metrics replaces the full binding list.
69
75
 
70
76
  ```bash
71
77
  ae-cli experiment experiment get --project-id 1 --exp-id exp_123
72
78
  ae-cli experiment experiment save --project-id 1 --req '{"expName":"Demo"}' --dry-run
73
- ae-cli experiment metric save --project-id 1 --req '{"metricId":"login_users","metricName":"Login users","createType":"event","goalDirection":"up","metricDesc":"Users who logged in","metricDefinition":{"type":"event","event":"login","aggregation":"user_count"}}' --dry-run
79
+ ae-cli experiment metric save --project-id 1 --req '{"metricId":"payment_gold_sum","metricName":"Payment gold sum","createType":"event","goalDirection":"up","metricDesc":"Gold sum for payments above 10","metricDefinition":{"type":"event","event":"payment","aggregation":"sum","property":"gold","filters":{"relation":"and","items":[{"field":"gold","operator":"gt","values":[10]}]}}}' --dry-run
74
80
  ae-cli experiment report metric-trend --project-id 1 --exp-id exp_123 --metric-id metric_1 --start-time 2026-07-01 --end-time 2026-07-07
75
81
  ```
76
82
 
@@ -92,7 +98,9 @@ Read [`save_build_guide.md`](references/save_build_guide.md) and
92
98
 
93
99
  ### Experiment
94
100
 
95
- `experiment experiment save`, `capability run experiment.experiment.save-submit`, `experiment experiment list`, `experiment experiment list-archived`, `experiment experiment get`, `experiment experiment ready-check`, `experiment experiment conflict-check`, `experiment experiment manage`, `experiment experiment update-group`, `experiment experiment batch-delete`, `experiment operation-log query`
101
+ `experiment experiment save`, `experiment experiment update-metrics`, `capability run experiment.experiment.save-submit`, `experiment experiment list`, `experiment experiment list-archived`, `experiment experiment get`, `experiment experiment ready-check`, `experiment experiment conflict-check`, `experiment experiment manage`, `experiment experiment update-group`, `experiment experiment batch-delete`, `experiment operation-log query`
102
+
103
+ Read [`manage_guardrail_metrics.md`](references/manage_guardrail_metrics.md) before assigning or replacing metric roles.
96
104
 
97
105
  ### Traffic Layer and Buckets
98
106
 
@@ -104,4 +112,6 @@ Read [`save_build_guide.md`](references/save_build_guide.md) and
104
112
 
105
113
  ### Metric and Feature
106
114
 
107
- `experiment metric save`, `experiment metric get`, `experiment metric list`, `experiment metric delete`, `experiment feature save`, `experiment feature update-status`, `experiment feature get`, `experiment feature list`, `experiment feature version-list`, `experiment feature operation-log query`, `experiment feature batch-delete`
115
+ `experiment metric save`, `experiment metric get`, `experiment metric list`, `experiment metric delete`, `experiment feature save`, `experiment feature update-status`, `experiment feature get`, `experiment feature list`, `experiment feature version-list`, `experiment feature operation-log query`, `experiment feature batch-delete`, `experiment feature whitelist list`, `experiment feature whitelist save`, `experiment feature whitelist update-status`, `experiment feature whitelist batch-delete`
116
+
117
+ Read [`manage_feature_whitelist.md`](references/manage_feature_whitelist.md) before querying or changing Feature whitelist rules.
@@ -0,0 +1,66 @@
1
+ # Feature Whitelist Rules
2
+
3
+ List, create, modify, enable, disable, or delete explicit Feature whitelist rules.
4
+
5
+ ## List
6
+
7
+ ```bash
8
+ ae-cli experiment feature whitelist list \
9
+ --project-id <id> --feature-key <feature_key>
10
+ ```
11
+
12
+ The result contains only explicit whitelist rules for the Feature. Each item exposes `rule_id`,
13
+ `feature_key`, `priority`, `status`, and a structured snake-case `whitelist` array. Use the returned
14
+ `rule_id` for modification, status changes, or deletion.
15
+
16
+ ## Save
17
+
18
+ ```bash
19
+ ae-cli experiment feature whitelist save \
20
+ --project-id <id> \
21
+ --feature-key <feature_key> \
22
+ --status enable \
23
+ --whitelist '[{"bucket_id":"#user_id","rules":[{"ids":["u1","u2"],"value":"on"}]}]'
24
+ ```
25
+
26
+ Pass `--rule-id` to modify an existing whitelist rule. Omit it to create a rule. The Hermes
27
+ Capability fixes the Atlas rule type to `targeting` and serializes the supplied buckets into the
28
+ server's explicit whitelist rule configuration.
29
+
30
+ Rules:
31
+
32
+ - Resolve the Feature with `experiment feature get` before writing.
33
+ - `bucket_id` is the split subject, such as `#user_id` or `#account_id`.
34
+ - Each bucket contains one or more rows with a non-empty `ids` array and a string `value`.
35
+ - An empty string Feature value is allowed. Bucket IDs cannot be empty or duplicated. IDs must be
36
+ unique within one bucket, while different buckets may use the same string ID.
37
+ - The server validates each value against the Feature type and limits the total ID count.
38
+ - Only one explicit whitelist rule can be enabled for the same Feature.
39
+ - Enabling, modifying, disabling, or deleting an enabled whitelist rule immediately creates a new
40
+ version and syncs RCC when the Feature itself is online.
41
+
42
+ ## Status
43
+
44
+ ```bash
45
+ ae-cli experiment feature whitelist update-status \
46
+ --project-id <id> --rule-id <rule_id> --status enable
47
+ ```
48
+
49
+ Valid status transitions exposed by this command are `enable` and `disable`.
50
+
51
+ ## Delete
52
+
53
+ ```bash
54
+ ae-cli experiment feature whitelist batch-delete \
55
+ --project-id <id> --rule-ids '["0001"]'
56
+ ```
57
+
58
+ Deletion is high risk and requires confirmation. Enabled whitelist rules may be deleted; Hermes
59
+ resynchronizes affected online Features afterward.
60
+
61
+ All four commands use Capability Gateway with CLI-token authentication:
62
+
63
+ - `experiment.feature_whitelist.list`
64
+ - `experiment.feature_whitelist.save`
65
+ - `experiment.feature_whitelist.update_status`
66
+ - `experiment.feature_whitelist.batch_delete`
@@ -0,0 +1,26 @@
1
+ # experiment experiment update-metrics
2
+
3
+ Replace the metric bindings of an existing experiment draft and assign metric roles, including
4
+ guardrail metrics.
5
+
6
+ ```bash
7
+ ae-cli experiment experiment update-metrics \
8
+ --project-id <id> \
9
+ --exp-id <exp_id> \
10
+ --metrics '[{"metricId":"conversion","metricRole":"primary"},{"metricId":"error_rate","metricRole":"guardrail"}]'
11
+ ```
12
+
13
+ ## Contract
14
+
15
+ - Discover every `metricId` with `experiment metric list`; never invent metric IDs.
16
+ - `--metrics` must be a non-empty array. Each item requires camelCase `metricId` and `metricRole`.
17
+ - `metricRole` is one of `primary`, `secondary`, or `guardrail`. Do not submit the internal
18
+ `observation` role; Hermes currently rejects it at save boundaries.
19
+ - This command replaces all saved metric bindings because Hermes treats a non-empty `metrics` list
20
+ in a draft patch as a replacement. Include bindings that must remain, not only the new guardrail.
21
+ - Guardrail is a binding role, not a separate metric type. Create the underlying metric first with
22
+ `experiment metric save` when it does not exist.
23
+ - At least one `primary` metric is still required before readiness succeeds.
24
+
25
+ Run with `--dry-run` first, then verify the persisted roles with `experiment experiment get` and
26
+ run `experiment experiment ready-check`.
@@ -104,7 +104,7 @@ ae-cli experiment experiment save --project-id 1 --req '{"expId":"exp_123","allo
104
104
  - `expCycle.cycleType` can be `day` or `sample`; when `cycleType=day`, `dayNum` is `1..90`. Blank cycle defaults to day + 30.
105
105
  - Before readiness, `groups` must be non-empty, contain exactly one control group (`isControl=1`), group allocations must sum to exactly `100`, and each `expGroupValue` must be a non-empty JSON string array.
106
106
  - Feature experiments must bind `featureKeyList` before readiness. `featureKeyList` contains Feature key strings, not Feature objects. The MCP currently supports one `featureKey` for feature experiments.
107
- - Metrics use `metricRole=primary|secondary|guardrail|observation`; before readiness at least one primary metric is required.
107
+ - Metrics use `metricRole=primary|secondary|guardrail`; the internal `observation` role is currently unavailable for saves. Before readiness at least one primary metric is required.
108
108
  - `targeting` replaces the saved targeting object when provided.
109
109
  - Custom audience QP must be supplied as the semantic object
110
110
  `targeting.definitionRequest`. Do not submit the internal `targeting.targetConfig`
@@ -21,9 +21,13 @@ See [`save_build_guide.md`](save_build_guide.md) / [`save_validate.md`](save_val
21
21
  - Supply metric QP as `req.metricDefinition`.
22
22
  - Never submit internal `metricConfig`, `calcType`, or an `Axxx` calculation code.
23
23
  - Experiment metrics currently accept event definitions only.
24
+ - Event-property comparisons belong in `metricDefinition.filters`. Each item uses
25
+ `field`, `operator`, and `values`; do not place `operator` or `value` directly on
26
+ `metricDefinition`.
24
27
  - Supported aggregations:
25
- - Event-count (no property): `total_count`, `user_count`, `active_days`
28
+ - Preset event metrics (omit `property`): `total_count`, `user_count`, `active_days`
26
29
  - Property-based (**`property` REQUIRED**): `sum`, `avg`, `max`, `distinct_count`
30
+ - `avg_per_user` (`A105`) is not supported for experiment metric creation.
27
31
 
28
32
  ### Property rule (mandatory)
29
33
 
@@ -38,6 +42,12 @@ When `aggregation` is `sum`, `avg`, `max`, or `distinct_count`:
38
42
 
39
43
  When `aggregation` is `total_count`, `user_count`, or `active_days`, omit `property`.
40
44
 
45
+ ### Preset event metric example (no property)
46
+
47
+ ```bash
48
+ ae-cli experiment metric save --project-id 1 --req '{"metricId":"payment_users","metricName":"Payment users","createType":"event","goalDirection":"up","metricDesc":"Users who triggered payment","metricDefinition":{"type":"event","event":"payment","aggregation":"user_count"}}'
49
+ ```
50
+
41
51
  ### Correct example (avg with property)
42
52
 
43
53
  ```bash
@@ -51,7 +61,11 @@ ae-cli experiment metric save --project-id 1 --req '{
51
61
  "type":"event",
52
62
  "event":"payment",
53
63
  "aggregation":"avg",
54
- "property":"amount"
64
+ "property":"amount",
65
+ "filters":{
66
+ "relation":"and",
67
+ "items":[{"field":"amount","operator":"gt","values":[10]}]
68
+ }
55
69
  }
56
70
  }'
57
71
  ```
@@ -69,11 +83,9 @@ ae-cli experiment metric save --project-id 1 --req '{
69
83
  }
70
84
  ```
71
85
 
72
- ### Event-count example (no property)
86
+ Filters use the semantic `filters` tree with `relation=and|or` and items containing
87
+ `field`, `operator`, and `values`. For the frontend example `gold > 10`, use:
73
88
 
74
- ```bash
75
- ae-cli experiment metric save --project-id 1 --req '{"metricId":"purchase_users","metricName":"Purchase users","createType":"event","goalDirection":"up","metricDesc":"Unique purchasers","metricDefinition":{"type":"event","event":"purchase","aggregation":"user_count"}}'
89
+ ```json
90
+ {"filters":{"relation":"and","items":[{"field":"gold","operator":"gt","values":[10]}]}}
76
91
  ```
77
-
78
- Filters use the semantic `filters` tree with `relation=and|or` and items containing
79
- `field`, `operator`, and `values`.