@thinkingai/ae-cli 6.0.48-customer.1 → 6.1.0-project-role-upsert.1

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 (144) hide show
  1. package/README.md +96 -36
  2. package/README.zh.md +96 -36
  3. package/dist/{auth-QPEVVBKT.js → auth-FUM37MHF.js} +236 -127
  4. package/dist/{capability-RUSV77CO.js → capability-AXFQW5WM.js} +49 -33
  5. package/dist/{chunk-FR2EDAQM.js → chunk-4P355ZWB.js} +69 -1
  6. package/dist/chunk-6ZIQV5GW.js +26 -0
  7. package/dist/chunk-ATSM5XAW.js +623 -0
  8. package/dist/{chunk-6QK7SYYY.js → chunk-BBEFP4SB.js} +29 -37
  9. package/dist/{chunk-KEWVSO64.js → chunk-CZU3V3DQ.js} +4 -15
  10. package/dist/chunk-ECBLHAZO.js +15 -0
  11. package/dist/{chunk-B5HMQAOM.js → chunk-I4WQAEYB.js} +1 -1
  12. package/dist/{chunk-NSIVXKJH.js → chunk-JDPEVVHR.js} +5 -4
  13. package/dist/{chunk-BE73PUFX.js → chunk-LNZBEQXW.js} +2 -2
  14. package/dist/{chunk-GJXRF7Y6.js → chunk-QJQZH5GQ.js} +47 -78
  15. package/dist/{chunk-BVDST5YT.js → chunk-RSG4ONOI.js} +7 -7
  16. package/dist/{chunk-JYMGHGCE.js → chunk-VXNMYUXU.js} +24 -13
  17. package/dist/{chunk-KZ6ZHF5J.js → chunk-WZ6YVQSF.js} +14 -14
  18. package/dist/{community-report-client-6OL6GBQW.js → community-report-client-XXWGSBSD.js} +2 -4
  19. package/dist/{config-XNMACCKX.js → config-EXUGQN5T.js} +8 -9
  20. package/dist/{data-integration-FZQQC3KW.js → data-integration-4NZ53OMT.js} +7 -9
  21. package/dist/index.js +61 -78
  22. package/dist/{local-data-upload-client-EFHDLXFG.js → local-data-upload-client-KYOKVYZV.js} +2 -4
  23. package/dist/{memory-HBJQ2GC5.js → memory-ATNKZNW5.js} +4 -6
  24. package/dist/{metadata-PGDJE5RQ.js → metadata-SOALPEA7.js} +7 -9
  25. package/dist/{model-BHLJ2QMT.js → model-E4JMQ4V2.js} +4 -6
  26. package/dist/{personal-semantic-preference-E5NZ56DN.js → personal-semantic-preference-LOF33N5X.js} +6 -8
  27. package/dist/project-semantic-RV6NA5LN.js +1113 -0
  28. package/dist/{sync-MUWPRM5I.js → sync-YV3E66IF.js} +6 -8
  29. package/dist/{te-agent-WQZTMEK4.js → te-agent-JB5T3PO7.js} +393 -90
  30. package/dist/{te-analysis-YWCSSLYL.js → te-analysis-TV2YZ4IC.js} +112 -30
  31. package/dist/{te-community-BNE6KREL.js → te-community-UDBI672N.js} +9 -32
  32. package/dist/{te-dataops-TXLKM2W6.js → te-dataops-ZLYOCXZ4.js} +19 -20
  33. package/dist/{te-engage-VEW4CJHK.js → te-engage-EUVMTUDJ.js} +67 -11
  34. package/dist/te-experiment-ESEYE2SK.js +1059 -0
  35. package/dist/{te-kb-BUD6N3NI.js → te-kb-WYQWHFSC.js} +595 -85
  36. package/dist/{te-system-44LZJDTQ.js → te-system-7G6F2LJA.js} +6 -8
  37. package/dist/{te-team-XMP47YXE.js → te-team-E7FBBXMQ.js} +6 -8
  38. package/dist/{update-UODFOZ4P.js → update-D47BUG25.js} +7 -8
  39. package/package.json +13 -9
  40. package/skills/ae-agent/SKILL.md +30 -13
  41. package/skills/ae-agent/references/agent-distribution.md +94 -0
  42. package/skills/ae-agent/references/approval-request.md +4 -0
  43. package/skills/ae-agent/references/command_index.md +9 -2
  44. package/skills/ae-agent/references/create-automation.md +20 -2
  45. package/skills/ae-agent/references/get-agent-context.md +70 -0
  46. package/skills/ae-agent/references/list-automations.md +18 -3
  47. package/skills/ae-agent/references/list-mcp-credentials.md +1 -1
  48. package/skills/ae-agent/references/mcp-token.md +3 -3
  49. package/skills/ae-agent/references/set-mcp-credential.md +0 -1
  50. package/skills/ae-agent/references/update-automation.md +18 -0
  51. package/skills/ae-analysis/SKILL.md +28 -3
  52. package/skills/ae-analysis/references/adhoc_run.md +2 -0
  53. package/skills/ae-analysis/references/ai_models.md +23 -3
  54. package/skills/ae-analysis/references/analysis_gateway_assets.md +2 -2
  55. package/skills/ae-analysis/references/command_index.md +8 -8
  56. package/skills/ae-analysis/references/cross_source_config.md +84 -0
  57. package/skills/ae-analysis/references/dashboard_update.md +1 -1
  58. package/skills/ae-analysis/references/personal_semantic_preference_add.md +1 -1
  59. package/skills/ae-analysis/references/personal_semantic_preference_get.md +3 -1
  60. package/skills/ae-analysis/references/personal_semantic_preference_list.md +3 -1
  61. package/skills/ae-analysis/references/personal_semantic_preference_update.md +1 -1
  62. package/skills/ae-analysis/references/project_role_upsert.md +32 -2
  63. package/skills/ae-analysis/references/user_tag_create.md +23 -1
  64. package/skills/ae-analysis/references/user_tag_models.md +9 -1
  65. package/skills/ae-analysis/references/user_tag_update.md +14 -2
  66. package/skills/ae-data-integration/SKILL.md +2 -1
  67. package/skills/ae-data-integration/references/dimension-routing.md +36 -0
  68. package/skills/ae-data-integration/references/local-analysis.md +2 -0
  69. package/skills/ae-data-integration/references/source-inspect.md +1 -1
  70. package/skills/ae-data-integration/references/ue-routing.md +17 -1
  71. package/skills/ae-engage/SKILL.md +2 -0
  72. package/skills/ae-engage/references/save-flow.md +37 -1
  73. package/skills/ae-experiment/SKILL.md +117 -0
  74. package/skills/ae-experiment/references/batch_delete_experiment.md +11 -0
  75. package/skills/ae-experiment/references/batch_delete_feature.md +11 -0
  76. package/skills/ae-experiment/references/batch_delete_traffic_layer.md +11 -0
  77. package/skills/ae-experiment/references/cancel_experiment_query_by_request_id.md +11 -0
  78. package/skills/ae-experiment/references/check_experiment_ready.md +17 -0
  79. package/skills/ae-experiment/references/check_experiment_traffic_layer_conflict.md +37 -0
  80. package/skills/ae-experiment/references/delete_metric.md +13 -0
  81. package/skills/ae-experiment/references/manage_experiment.md +17 -0
  82. package/skills/ae-experiment/references/manage_feature_status.md +11 -0
  83. package/skills/ae-experiment/references/manage_feature_whitelist.md +66 -0
  84. package/skills/ae-experiment/references/manage_guardrail_metrics.md +26 -0
  85. package/skills/ae-experiment/references/query_bucket_list.md +12 -0
  86. package/skills/ae-experiment/references/query_experiment_detail.md +19 -0
  87. package/skills/ae-experiment/references/query_experiment_list.md +22 -0
  88. package/skills/ae-experiment/references/query_experiment_list_archived.md +18 -0
  89. package/skills/ae-experiment/references/query_experiment_metric_trend.md +12 -0
  90. package/skills/ae-experiment/references/query_experiment_operation_log.md +17 -0
  91. package/skills/ae-experiment/references/query_experiment_report_summary.md +12 -0
  92. package/skills/ae-experiment/references/query_experiment_sample_size_report.md +13 -0
  93. package/skills/ae-experiment/references/query_feature_detail.md +14 -0
  94. package/skills/ae-experiment/references/query_feature_list.md +12 -0
  95. package/skills/ae-experiment/references/query_feature_operation_log.md +19 -0
  96. package/skills/ae-experiment/references/query_feature_version_list.md +20 -0
  97. package/skills/ae-experiment/references/query_metric_detail.md +18 -0
  98. package/skills/ae-experiment/references/query_metric_list.md +15 -0
  99. package/skills/ae-experiment/references/query_traffic_layer_detail.md +13 -0
  100. package/skills/ae-experiment/references/query_traffic_layer_list.md +12 -0
  101. package/skills/ae-experiment/references/save_build_guide.md +39 -0
  102. package/skills/ae-experiment/references/save_experiment.md +210 -0
  103. package/skills/ae-experiment/references/save_feature.md +13 -0
  104. package/skills/ae-experiment/references/save_metric.md +91 -0
  105. package/skills/ae-experiment/references/save_submit_experiment.md +16 -0
  106. package/skills/ae-experiment/references/save_traffic_layer.md +13 -0
  107. package/skills/ae-experiment/references/save_validate.md +33 -0
  108. package/skills/ae-experiment/references/update_experiment_group.md +20 -0
  109. package/skills/ae-experiment-design/SKILL.md +149 -0
  110. package/skills/ae-experiment-design/agents/openai.yaml +4 -0
  111. package/skills/ae-experiment-design/references/client-experiment-sdk.md +147 -0
  112. package/skills/ae-experiment-design/references/experiment-creation.md +108 -0
  113. package/skills/ae-experiment-design/references/experiment-sdk-contract.md +100 -0
  114. package/skills/ae-experiment-design/references/exposure-contract.md +91 -0
  115. package/skills/ae-experiment-design/references/hybrid-experiment-sdk.md +74 -0
  116. package/skills/ae-experiment-design/references/metric-readiness.md +143 -0
  117. package/skills/ae-experiment-design/references/platform-operations.md +105 -0
  118. package/skills/ae-experiment-design/references/sdk-index.md +76 -0
  119. package/skills/ae-experiment-design/references/sdk-integration.md +114 -0
  120. package/skills/ae-experiment-design/references/sdk-troubleshooting.md +139 -0
  121. package/skills/ae-experiment-design/references/server-experiment-sdk.md +78 -0
  122. package/skills/ae-experiment-design/scripts/calculate_experiment_plan.py +450 -0
  123. package/skills/ae-experiment-insight/SKILL.md +149 -0
  124. package/skills/ae-experiment-insight/agents/openai.yaml +4 -0
  125. package/skills/ae-experiment-insight/references/decision-framework.md +69 -0
  126. package/skills/ae-experiment-insight/references/diagnostic-playbook.md +225 -0
  127. package/skills/ae-experiment-insight/references/platform-operations.md +82 -0
  128. package/skills/ae-experiment-insight/scripts/analyze_experiment.py +478 -0
  129. package/skills/ae-generate-tracking-plan/SKILL.md +16 -5
  130. package/skills/ae-kb/SKILL.md +107 -36
  131. package/skills/ae-kb/references/query-workflow.md +59 -29
  132. package/skills/ae-kb/references/versions.md +46 -0
  133. package/skills/ae-project-semantic/SKILL.md +193 -0
  134. package/skills/ae-project-semantic/references/query-routing-v5.md +165 -0
  135. package/skills/ae-project-semantic/references/recommendation-quality.md +68 -0
  136. package/skills/ae-system/SKILL.md +1 -1
  137. package/skills/ae-use-agent/SKILL.md +42 -0
  138. package/skills/ae-use-agent/references/local-agent.md +114 -0
  139. package/dist/auth-UMJAA72O.js +0 -15
  140. package/dist/chunk-533JK3YX.js +0 -72
  141. package/dist/chunk-O6K2ODUE.js +0 -318
  142. package/dist/chunk-RWXIXOZG.js +0 -326
  143. package/dist/client-N7NGZUNI.js +0 -204
  144. package/skills/ae-agent/references/auto-provision-mcp-credentials.md +0 -57
@@ -12,8 +12,10 @@ ae-cli personal-semantic-preference list --project-id <project_id>
12
12
 
13
13
  Input uses `project_id` only. Do not add pagination parameters: the backend returns a compact catalog intended for agent context.
14
14
 
15
- Do not use this command for shared knowledge, metadata catalogs, report/dashboard lists, or complete asset discovery. It only returns the current user's personal semantic preferences in the current project.
15
+ Do not use this command for project semantics, shared knowledge, metadata catalogs, report/dashboard lists, or complete asset discovery. It only returns the current user's personal semantic preferences in the current project.
16
16
 
17
17
  Output is the gateway envelope. `data.items[]` contains only `id`, `context_type`, `title`, truncated `summary`, limited `keywords`, `resource_ref_count`, distinct `resource_types`, and `revision`; it deliberately omits content, full asset references, heat, and timestamps. `data.returned_count` is at most 200, `data.truncated` says whether entries were omitted, and `data.selection_policy` is `HOT_160_PLUS_RECENT_40`: up to 160 highest-heat items plus up to 40 recently changed items not already selected. The backend may return fewer items to keep the data payload within 64 KiB.
18
18
 
19
19
  If one returned item is actually adopted to interpret the user's request, call `ae-cli personal-semantic-preference get --project-id <project_id> --id <preference_id> --mark-used` before using its full content. Do not mark an item used when it was only inspected or rejected.
20
+
21
+ Compare a likely match with the published project semantic catalog. Published project semantics remain the formal project-wide authority; personal items provide current-user defaults and working interpretations. If they conflict, use the project semantic for the formal result, explicitly disclose the personal difference, and do not mark the personal item used unless the user explicitly adopts it as a labeled alternative.
@@ -12,7 +12,7 @@ ae-cli personal-semantic-preference update --project-id <project_id> --id <prefe
12
12
 
13
13
  The update replaces all editable fields. Include the full intended `title`, `summary`, `content`, keywords, and asset bindings rather than a partial patch. `asset_context` requires 1 to 50 complete ordered `resource_refs`; other context types cannot contain non-empty refs.
14
14
 
15
- This command updates only the current-user preference. Do not block the update merely because the same content may benefit other users, and do not imply that the saved preference is shared authority.
15
+ This command updates only the current-user preference; it does not update, approve, or publish project semantics. Do not block the update merely because the same content may benefit other users, and do not imply that the saved preference is shared authority. Keep project-candidate recommendation separate and ask before submitting it.
16
16
 
17
17
  Keep future governance and lifecycle handling out of the stored content. Do not use this command for shared knowledge, standalone metadata facts, reports, dashboards, transient task details, one-off analysis results, or automatic stale/expired preference handling.
18
18
 
@@ -8,12 +8,42 @@ Command:
8
8
 
9
9
  ```bash
10
10
  ae-cli project role upsert --project-id <project_id> --payload <payload>
11
+ ae-cli project role upsert --validate --project-id <project_id> --payload <payload>
11
12
  ae-cli project role upsert --dry-run --project-id <project_id> --payload <payload>
12
13
  ```
13
14
 
14
15
  Capability id: `project.role.upsert`.
15
16
 
16
- Input sends `project_id`, `payload`. Payload keys, JSON arrays, and projection fields must follow the common-service snake_case input schema.
17
+ Input sends `project_id`, `payload`. Payload keys must use snake_case.
18
+
19
+ ## Payload contract
20
+
21
+ `role_func_list` is required and must be a non-empty array of objects. Every item requires:
22
+
23
+ - `function_name`: non-empty string. Resolve valid values with `ae-cli project function list` instead of guessing IDs or sending numeric function IDs.
24
+ - `has_power`: integer `0` or `1` only. Use `1` to select the function and `0` to leave it unselected.
25
+
26
+ For role creation, omit `role_name` and provide `role_desc` with 1 to 80 characters. For an update, provide the existing `role_name`; `role_desc` may remain omitted for compatibility.
27
+
28
+ Functions omitted from `role_func_list` are completed by the service with their permission metadata and `has_power=0`. Do not attempt to replace an object item with a number or string.
29
+
30
+ Create example:
31
+
32
+ ```bash
33
+ ae-cli project role upsert \
34
+ --project-id 196 \
35
+ --payload '{"role_desc":"Data analyst","role_func_list":[{"function_name":"viewReport","has_power":1}]}'
36
+ ```
37
+
38
+ Update example:
39
+
40
+ ```bash
41
+ ae-cli project role upsert \
42
+ --project-id 196 \
43
+ --payload '{"role_name":"custom_role","role_func_list":[{"function_name":"viewReport","has_power":1}]}'
44
+ ```
45
+
46
+ Run with `--validate` first when constructing the payload dynamically. Invalid item types, missing fields, an empty list, or a `has_power` value outside `0` and `1` return a validation error before the role is saved.
17
47
 
18
48
  Output uses the gateway envelope: success is `ok=true,data,meta`; failure is `ok=false,error`. Preserve `request_id` and `invocation_id` when present.
19
49
 
@@ -21,4 +51,4 @@ Output uses the gateway envelope: success is `ok=true,data,meta`; failure is `ok
21
51
  | Parameter | Required | Description |
22
52
  |---|---|---|
23
53
  | `--project-id` | Yes | Numeric project ID. |
24
- | `--payload` | Yes | Role save payload matching RoleSaveRequestDTO in snake_case. |
54
+ | `--payload` | Yes | Role payload with a non-empty `role_func_list` object array; each item contains `function_name` and `has_power` (`0` or `1`). |
@@ -6,7 +6,7 @@ Do not use it for uploaded-ID tags; use `user-tag create-id`. A successful creat
6
6
 
7
7
  The response reports this directly: `computation.triggered_automatically=true`, `computation.status=submitted`, and `result_freshness.is_stale=true`. Follow `next_action`; when it is `poll_get`, invoke `next_capability_id` with the exact `next_input` returned by the command.
8
8
 
9
- Flags: `--project-id`, `--tag-name`, `--display-name`, `--definition-request` required. Optional: `--authenticated-only`, `--zone-offset`, `--entity-id`. The tag type comes from `definition_request.type`.
9
+ Flags: `--project-id`, `--tag-name`, `--display-name`, `--definition-request` required. Optional: `--authenticated-only`, `--zone-offset`, `--entity-id`, `--enable-auto-refresh`, `--auto-refresh-schedule`, `--auto-refresh-cron`. The tag type comes from `definition_request.type`.
10
10
 
11
11
  `tag_name` is a machine identifier: 1-80 characters, starts with a letter, and contains only letters, digits, or underscores. `display_name` is 1-80 characters. The CLI rejects violations before dispatch.
12
12
 
@@ -23,3 +23,25 @@ First/last tag for this month:
23
23
  ```bash
24
24
  ae-cli analysis user-tag create --project-id <project_id> --tag-name latest_platform_this_month --display-name "Latest Platform This Month" --definition-request '{"type":"first_last","first_last":{"event":"login","occurrence":"last","property":"platform","time_range":{"mode":"recent","unit":"month","value":1}}}'
25
25
  ```
26
+
27
+ Periodic refresh can be configured in this same create operation. It is separate from the initial computation. Omitted scheduling flags leave periodic refresh disabled; supplying a schedule enables it. `--enable-auto-refresh true` requires a schedule on create. Do not combine `--enable-auto-refresh false` with a schedule, or pass both schedule forms.
28
+
29
+ Append one of these options to the create command:
30
+
31
+ ```bash
32
+ # Every day at 02:30 in the tag timezone
33
+ --auto-refresh-schedule '{"frequency":"daily","time":"02:30"}'
34
+
35
+ # Monday and Sunday at 09:00 (ISO weekdays: 1=Monday, 7=Sunday)
36
+ --auto-refresh-schedule '{"frequency":"weekly","time":"09:00","weekdays":[1,7]}'
37
+
38
+ # The 1st and 15th of each month at 06:00
39
+ --auto-refresh-schedule '{"frequency":"monthly","time":"06:00","month_days":[1,15]}'
40
+
41
+ # Custom Quartz schedule, including multiple executions per day
42
+ --auto-refresh-cron '0 0/30 8-18 * * ? *'
43
+ ```
44
+
45
+ `time` uses 24-hour `HH:mm`. `month_days` accepts 1-31; dates absent from a month are skipped. Weekly/monthly schedules require their respective day array; other frequencies reject those fields. The structured form preserves the page's daily/weekly/monthly frequency selection. Cron uses the page's custom schedule mode and preserves every cron field.
46
+
47
+ Schedules use the tag timezone. Use the existing `--zone-offset` only with an offset supported by the project; omit it to use the project's default behavior. Inspect `user-tag get` for `enable_auto_refresh` (1=enabled, 0=disabled), `scheduler_ui_config`, and `cluster_zone_offset` after creation.
@@ -24,12 +24,20 @@ Top-level `type` is exactly one of `condition`, `metric`, `first_last`, or `sql`
24
24
 
25
25
  ## Metric tag
26
26
 
27
- Required: `event`, `aggregation`. `property`, `time_range`, and `filters` are optional. Filters support only event properties and user properties. A string `field` is an event property; use `{name,type:"user_property"}` for a user property.
27
+ Required: `event`, `aggregation`. `property`, `percentile`, `time_range`, and `filters` are optional. Filters support only event properties and user properties. A string `field` is an event property; use `{name,type:"user_property"}` for a user property.
28
+
29
+ Use `aggregation=percentile` with a numeric event `property` and pass `percentile`. Supported percentile values match the page controls: `5`, `10`, `20`, `25`, `30`, `40`, `60`, `70`, `75`, `80`, `90`, `95`, and `99`. The `percentile` field is required for percentile aggregation and is rejected for every other aggregation.
28
30
 
29
31
  ```json
30
32
  {"type":"metric","metric":{"event":"pay","aggregation":"sum","property":"amount","time_range":{"mode":"previous","unit":"day","value":30},"filters":{"relation":"and","items":[{"field":"channel","operator":"eq","values":["app"]},{"field":{"name":"country","type":"user_property"},"operator":"eq","values":["US"]}]}}}
31
33
  ```
32
34
 
35
+ Percentile example:
36
+
37
+ ```json
38
+ {"type":"metric","metric":{"event":"pay","aggregation":"percentile","property":"amount","percentile":90}}
39
+ ```
40
+
33
41
  ## First/last tag
34
42
 
35
43
  Required: `event`, `occurrence=first|last`, and exactly one value source: `calculation` or `property`. `time_range` and `filters` are optional. Filters support only event properties and user properties. A string `field` is an event property; use `{name,type:"user_property"}` for a user property. Supplying neither or both value sources is rejected before execution. Use the semantic time mappings in [`audience_models.md`](audience_models.md) for dynamic ranges such as today, this month, or a fixed start date through today.
@@ -2,11 +2,11 @@
2
2
 
3
3
  Update a user tag. Discover the exact `tag_name` first.
4
4
 
5
- Do not use it for ID-file value replacement or to create a missing tag. Supplying `--definition-request` automatically starts recomputation after the definition is updated; do not call `user-tag refresh` afterward. Updating only `--display-name` or `--remark` does not recompute. `--auto-refresh-cron` changes an existing enabled auto-refresh schedule and does not enable auto refresh. A successful update means the definition was saved, not that the new result is complete. Record the current `refresh_time` before updating, then poll `user-tag get` until `progress=100` and `refresh_time` advances before using `users_num` or querying members.
5
+ Do not use it for ID-file value replacement or to create a missing tag. Supplying `--definition-request` automatically starts recomputation after the definition is updated; do not call `user-tag refresh` afterward. Updating only `--display-name` or `--remark` does not recompute. A schedule-only update changes periodic refresh without starting immediate recomputation. `--auto-refresh-cron` or `--auto-refresh-schedule` can enable periodic refresh directly, including on a previously disabled tag. A successful update means the definition was saved, not that the new result is complete. Record the current `refresh_time` before updating, then poll `user-tag get` until `progress=100` and `refresh_time` advances before using `users_num` or querying members.
6
6
 
7
7
  The response distinguishes both paths. A definition update returns `computation.triggered_automatically=true`, `result_freshness.is_stale=true`, and normally `next_action=poll_get` with an exact capability/input pair. A display-name/remark-only update returns `computation.status=not_triggered`, `result_freshness.status=fresh`, and `next_action=none`.
8
8
 
9
- Flags: `--project-id`, `--tag-name` required. Optional: `--display-name`, `--definition-request`, `--authenticated-only`, `--remark`, `--zone-offset`, `--auto-refresh-cron`. The tag type comes from `definition_request.type` when the definition changes.
9
+ Flags: `--project-id`, `--tag-name` required. Optional: `--display-name`, `--definition-request`, `--authenticated-only`, `--remark`, `--zone-offset`, `--enable-auto-refresh`, `--auto-refresh-schedule`, `--auto-refresh-cron`. The tag type comes from `definition_request.type` when the definition changes.
10
10
 
11
11
  `display_name` is at most 80 characters and `remark` is at most 400 characters. The CLI rejects violations before dispatch. `tag_name` is an existing exact identifier and cannot be renamed by update.
12
12
 
@@ -17,3 +17,15 @@ ae-cli analysis user-tag update --project-id <project_id> --tag-name user_level
17
17
 
18
18
  ae-cli analysis user-tag update --project-id <project_id> --tag-name user_level --auto-refresh-cron '0 30 2 * * ? *'
19
19
  ```
20
+
21
+ Omitting scheduling flags preserves the existing enable state and schedule, including during a definition update. Omitting `--zone-offset` preserves the saved tag timezone. `--enable-auto-refresh true` can reuse an existing saved plan; if none exists, provide a new schedule. `--enable-auto-refresh false` disables periodic refresh. Do not combine false with a schedule or pass both schedule forms. Structured schedule fields and timezone rules are described in [user_tag_create.md](user_tag_create.md).
22
+
23
+ ```bash
24
+ # Enable daily refresh in one update
25
+ ae-cli analysis user-tag update --project-id <project_id> --tag-name user_level --auto-refresh-schedule '{"frequency":"daily","time":"02:30"}'
26
+
27
+ # Disable periodic refresh
28
+ ae-cli analysis user-tag update --project-id <project_id> --tag-name user_level --enable-auto-refresh false
29
+ ```
30
+
31
+ Read `user-tag get` after updating to verify `enable_auto_refresh` (1=enabled, 0=disabled), `scheduler_ui_config`, and `cluster_zone_offset`. Schedule-only updates return `computation.status=not_triggered` and `next_action=none`.
@@ -36,6 +36,7 @@ Use this skill when the user wants to bring a **local data file** (CSV/TSV/TXT/J
36
36
  | Generate / upload a project-level tracking plan (source material is PRD / chat / template / code; deliverable is a real platform tracking plan) | ae-generate-tracking-plan |
37
37
  | Upload documents / URLs to a knowledge base | ae-kb |
38
38
  | Reports / dashboards / queries / governance on data already in AE | ae-analysis |
39
+ | Dimension / dictionary data (a stable-entity lookup — city / product / device) to load as a dimension table bound to a property | ae-metadata |
39
40
 
40
41
  This skill also produces a tracking-plan draft (`source_type: data`) as a governance prerequisite; that draft is an input to ae-generate-tracking-plan, not a substitute for its five-phase platform plan.
41
42
 
@@ -43,7 +44,7 @@ This skill also produces a tracking-plan draft (`source_type: data`) as a govern
43
44
 
44
45
  Walk the four submodules in order. Each submodule is its own reference; follow it and come back here for the next step.
45
46
 
46
- 1. **Source — business identification.** Read [references/source-inspect.md](references/source-inspect.md). Profile every file fully, infer its business meaning using business-doc / user-prompt priors, then pick a branch via [references/ue-routing.md](references/ue-routing.md).
47
+ 1. **Source — business identification.** Read [references/source-inspect.md](references/source-inspect.md). Profile every file fully, infer its business meaning using business-doc / user-prompt priors, then pick a branch via [references/ue-routing.md](references/ue-routing.md): UE ingestion, dimension routing ([references/dimension-routing.md](references/dimension-routing.md)), or local analysis.
47
48
  2. **Reuse check.** If the profile is `ue_eligible`, read [references/reuse.md](references/reuse.md) and match the recommended mapping against the handoff index. `reuse` searches the current directory's `.ae-cli/data-integration/` upward, then `~/.ae-cli/data-integration/`, so a package written elsewhere is still found. A match proposes a frozen package; after one explicit confirmation, run the returned `transform.mjs` command and jump to Sink (step 5). No match → continue.
48
49
  3. **Tracking plan.** Read [references/tracking-plan.md](references/tracking-plan.md). The plan is generated from the mapping (`plan --mapping`), so confirm the recommended mapping's key system fields with the user first — `mode`, `#account_id`/`#distinct_id`, `#time` + timezone, `#event_name`, `#ip`/`#uuid` (see [references/transform.md](references/transform.md) steps 1–5) — then generate the event/property plan and get a single explicit confirmation from the user before touching data. The plan is a separate, required deliverable from the transform mapping: a user who supplies a column→field mapping directly has **not** completed this step, so build the plan from the confirmed mapping anyway. `user_set` still requires a plan (no events; every property becomes a user property). This step runs for **every** file: a second or later file merges its new events and properties into the existing project plan (tracking-plan.md step 4) — an existing plan is never a reason to skip it.
49
50
  4. **Transform.** Read [references/transform.md](references/transform.md). Map columns to AE system fields and properties, convert, and quarantine dirty rows per [references/ue-mapping.md](references/ue-mapping.md).
@@ -0,0 +1,36 @@
1
+ # Dimension routing
2
+
3
+ Use this reference after [ue-routing.md](ue-routing.md) has classified the file as dimension data — a stable-entity lookup with no row-level identity or event time. It covers the handoff to ae-metadata; this skill does not ingest dimension data itself.
4
+
5
+ ## What dimension data is
6
+
7
+ Judge by content, never by file extension — CSV / TSV / TXT / JSON / JSONL / XLS / XLSX can all be dimension data. The classification signals live in [ue-routing.md](ue-routing.md): no row-level identity, no row-level event time, finite entity enumeration, and a join key shared with event data.
8
+
9
+ Dimension data is not the only file that fails UE prerequisites. Aggregates, pivot tables, and cumulative snapshots also lack identity/time, but those are local-analysis material, not dictionaries. The tell is the entity shape and the join key: a dimension table maps one entity code to its attributes (`city_code` → name / level), while an aggregate summarizes many rows into one measure.
10
+
11
+ Low confidence is a proposal, never a silent decision — ask the user instead of routing automatically.
12
+
13
+ ## Handoff to ae-metadata
14
+
15
+ Extract the dimension sheet / file to CSV, then hand the following commands to ae-metadata. The sequence lists entry points only; full flags live in ae-metadata's references.
16
+
17
+ Bind prerequisite (confirm before creating the table):
18
+
19
+ - The table binds to an existing property (`property_name` + `property_scope` = user or event). That property usually appears once event/user data is uploaded first (e.g. events carrying `city_code`), so dimension binding is a second-phase action after data lands.
20
+ - If the target property does not exist yet, create it first via ae-analysis metadata or a tracking plan. Never invent a property name.
21
+
22
+ Entry command sequence:
23
+
24
+ ```bash
25
+ # 1. Extract the dimension sheet/file to CSV (metadata upload accepts CSV only,
26
+ # purpose data_table.csv)
27
+ ae-cli analysis input-file upload --project-id <id> --purpose data_table.csv --file <dim.csv>
28
+ # 2. Create + bind in one step (or split into csv-write + bind-existing)
29
+ ae-cli metadata property create-and-bind-csv-dimension-table --project-id <id> \
30
+ --property-name <p> --property-scope user|event --input-file-id ifile_xxx
31
+ # 3. Later dictionary changes (add/update/delete):
32
+ ae-cli metadata data-table csv-write --operation incremental_update|replace_update \
33
+ --data-table-id <id> --input-file-id ifile_xxx
34
+ ```
35
+
36
+ Binding model: AE attaches a dimension table to a user/event property, turning it into a dict property whose values join through the table's key column to expand `--dict-columns`. See ae-metadata's dimension-table reference for the full flags.
@@ -1,5 +1,7 @@
1
1
  # Local analysis
2
2
 
3
+ Dimension / dictionary data (a stable-entity lookup with a join key) is not local-analysis material — it routes to ae-metadata as a dimension table. See [ue-routing.md](ue-routing.md) and [dimension-routing.md](dimension-routing.md).
4
+
3
5
  Keep the source on the local machine. Generated scripts and reports belong under `.ae-cli/data-integration/runs/<run-id>/` with restrictive permissions.
4
6
  Set the directory to `0700` and generated scripts/reports to `0600`.
5
7
 
@@ -63,7 +63,7 @@ Summarize both — report the shape of the distribution and the names of the val
63
63
  - **Excel date cells** — a cell whose number format is a date or date+time is read as the wall-clock timestamp shown in Excel, not as the Excel serial number stored behind it, so the column infers as `datetime` and can serve as the time field. Inspect lists every such column in a warning. Treat that warning as a question to the user, not as a note: the same column profiled as `number` before this behavior existed, so if any part of this file was already sent to AE, the property may have been received as a number and its type is now locked — it cannot be changed to datetime, and the column has to be re-sent under a new property name. Ask whether the column was uploaded before, and only map it once the user answers. Elapsed-duration formats (`[h]:mm:ss` and the equivalent built-ins) are durations rather than points in time and stay `number`.
64
64
  - **Excel formula cells** — a spreadsheet stores a formula and, next to it, the result Excel last computed. That cached result is the value: it is read normally, including a result of `0` or `""`, which are real values and not blanks. This tool never evaluates a formula and never guesses a result, so a cell holding a formula the file never computed has nothing to upload; it is read as missing and counted, as is an Excel error value (`#N/A`, `#DIV/0!`, …). Inspect reports the counts per column in a warning and `convert` repeats them in `manifest.output.unreadable_cells`. Report them: the rows are kept and the record count is unchanged, so this is the only explanation for a column that is empty in AE while the spreadsheet looks full. When a column that matters reads as missing this way, ask the user to recalculate and re-export in Excel, or to export values instead of formulas, before uploading. This covers XLSX; a legacy `.xls` workbook goes through a different parser and is not counted here.
65
65
  - **Merged cells, hidden rows, and hidden columns** — a sheet maintained by hand merges a label down the rows it covers (`区域` spanning one region's block). Excel keeps that value on the block's first row only and stores every row below it as an empty cell, so a column that looks full on screen arrives mostly missing, and the AE property built from it would be empty for most events. The same worksheet may also hide a row inside a data block or hide a whole column. None of this travels with a row, so inspect scans the worksheet structure separately and reports it under `xlsx_structure`: `merged_ranges` with `merged_range_samples` (references such as `A3:A5`, never cell text), `merged_covered_cells` per column, `hidden_rows` with `hidden_row_samples` (source row numbers as Excel numbers them), and `hidden_columns` by header name. The default read is unchanged, so the report is a question for the user, and each answer is a flag: `--fill-merged-cells` copies each block's value into the cells its own range covers — bounded to the range, never overwriting a value that is there and never inventing one when the block's own cell is empty, so it is not a forward fill; `--exclude-hidden-rows` leaves hidden rows out. Neither is on by default: those cells really are empty in the file, and a row hidden inside a data block may still be real data — unlike a hidden *worksheet* (below), which is excluded by default. Hidden columns have no flag at all; when the user confirms one is not data, list it in the mapping's `exclude_columns`. Both flags are carried into the recommended mapping as `fill_merged_cells` / `exclude_hidden_rows`, which is what makes `convert` read the rows inspect profiled — `convert` has no read flags of its own — and `convert` repeats the findings in `manifest.output.xlsx_structure`, the only record of a layout the converted rows no longer show. This covers XLSX; a legacy `.xls` workbook is not scanned, so ask the user about merged labels and hidden rows there instead of trusting silence.
66
- - **Hidden worksheets** — a worksheet hidden in the workbook is left out of the `--data-set` candidates and out of `--merge-sheets`, because a sheet the file does not show is usually scratch space, a lookup table, or a superseded draft rather than rows anyone meant to upload. Inspect lists each one under `excluded_sheets` (with `reason: hidden`); report those names to the user, since they are the only explanation for a row count lower than the workbook appears to hold. Their headers are also left out of `header_consistency`, so a stale hidden draft cannot make a mergeable workbook look ragged. A hidden sheet stays readable when the user names it in `--data-set` — the command then warns on stderr that the selected sheet is hidden. Only pass a hidden sheet after the user says that is what they want. When *every* worksheet is hidden there is no candidate left, and inspect fails with `LOCAL_DATA_ALL_DATA_SETS_HIDDEN` whose hint lists the hidden sheets; treat that as a question about which sheet holds the real data, not as an unreadable file. This detection covers XLSX only: a legacy `.xls` workbook's sheet list is unfiltered, so a hidden sheet there still appears as a candidate and is still merged — for `.xls`, ask the user to confirm the sheet list instead of trusting it.
66
+ - **Hidden worksheets** — a worksheet hidden in the workbook is left out of the `--data-set` candidates and out of `--merge-sheets`, because a sheet the file does not show is usually scratch space or a superseded draft rather than rows anyone meant to upload, but a hidden sheet can also be a dimension / dictionary table that is meant to be loaded, and that goes through dimension routing instead of being dismissed as scratch. Inspect lists each one under `excluded_sheets` (with `reason: hidden`); report those names to the user, since they are the only explanation for a row count lower than the workbook appears to hold. Their headers are also left out of `header_consistency`, so a stale hidden draft cannot make a mergeable workbook look ragged. A hidden sheet stays readable when the user names it in `--data-set` — the command then warns on stderr that the selected sheet is hidden. Only pass a hidden sheet after the user says that is what they want. When *every* worksheet is hidden there is no candidate left, and inspect fails with `LOCAL_DATA_ALL_DATA_SETS_HIDDEN` whose hint lists the hidden sheets; treat that as a question about which sheet holds the real data, not as an unreadable file. This detection covers XLSX only: a legacy `.xls` workbook's sheet list is unfiltered, so a hidden sheet there still appears as a candidate and is still merged — for `.xls`, ask the user to confirm the sheet list instead of trusting it.
67
67
  - **Excel sheets** — `--merge-sheets` streams every visible worksheet in file order instead of a single selected sheet; otherwise ask which sheet/`--data-set` to use. Inspect also reports `header_consistency` (`all_same` or `different`) across a workbook's sheets, with `header_details` listing each sheet's header row when they differ; prefer `--merge-sheets` only when headers match. Matching headers establish a shared structure, not disjoint rows: a detail sheet and a summary sheet, or `1月` and `1月修订版`, usually carry identical headers and would be merged and reported twice over. Before merging, confirm with the user that the sources are mutually exclusive partitions (one month per sheet, no overlap) rather than overlapping, revised, or derived views of the same rows, and show each sheet's row count and time coverage range in that confirmation so an overlap is visible. The same rule applies to repeated `--input-file`.
68
68
  - **Multi-file type conflicts** — when the same column has different inferred types across files, present each conflict and resolve with `--type-resolutions` on `convert` (see [transform](transform.md)).
69
69
 
@@ -20,7 +20,7 @@ Classification order:
20
20
  5. Rows that mix track and user-profile facts in one file use `mixed` with a `record_type_field`; require explicit review.
21
21
  6. Low-confidence output is a proposal, never silent approval.
22
22
 
23
- Aggregated metrics, pivot tables, cross-tabs, model outputs, free-form documents, and records without real identity/time should normally use local analysis.
23
+ Aggregated metrics, pivot tables, cross-tabs, model outputs, and free-form documents should normally use local analysis. Records without real identity/time are checked against dimension routing next and fall to local analysis only if they are not a stable-entity lookup.
24
24
 
25
25
  ### Time coverage is not native granularity
26
26
 
@@ -44,6 +44,22 @@ point, and do not proceed until they answer:
44
44
  An unanswered question, a cumulative snapshot, or overlapping periods route to local analysis
45
45
  instead.
46
46
 
47
+ ## Route to dimension table
48
+
49
+ A dimension / dictionary table describes stable entities (city, product, device): a lookup that maps an entity code to its attributes. It has no row-level identity or event time, so it fails the UE prerequisites above, but it is not local-analysis material either — it belongs in AE as a dimension table bound to a property.
50
+
51
+ Classification order (UE first, dimension second, local analysis last):
52
+
53
+ 1. Satisfy the UE must-holds above → UE ingestion wins; never route an identity/time-bearing file here.
54
+ 2. Fail the UE prerequisites **and** match most of these dimension signals → dimension routing:
55
+ - No row-level identity: no `account_id` / `distinct_id` column. A `code` / `id` / `no` key is an entity code, not a user identity.
56
+ - No row-level event time: no `#time` column. If time exists, it is an effective / expiry interval, not an event occurrence.
57
+ - Finite enumeration: few rows, each describing one entity's attributes (code → name / level), not facts accumulating over time.
58
+ - A join key: a column shared with event data (`city_code`, `sku_id`, `device_id`) whose values are descriptive attributes, not measures.
59
+ 3. Otherwise → local analysis.
60
+
61
+ See [references/dimension-routing.md](references/dimension-routing.md) for the handoff.
62
+
47
63
  ## Route to local analysis
48
64
 
49
65
  Choose local analysis when:
@@ -398,6 +398,8 @@ When the user wants to "create a flow / generate a flow canvas / save a flow", d
398
398
  3. Build condition-related nodes with semantic `targetDefinitionRequest` and
399
399
  `triggerDefinition` objects. Resolve real event and property names through Analysis metadata;
400
400
  do not create an intermediate cluster merely to obtain persisted QP.
401
+ For `ab_split_flow` indicators, use `indicatorsDef[].eventDefinition`; always provide the
402
+ aggregate `operator`/`value` and every event-property filter's `operator`/`values`.
401
403
 
402
404
  4. Before building touchpoint nodes such as `message_push`, `wechat_push`, or `webhook_push`, you must call:
403
405
 
@@ -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
@@ -0,0 +1,117 @@
1
+ ---
2
+ name: ae-experiment
3
+ version: 1.0.1
4
+ description: "Use when managing Atlas AB experiments, traffic layers, Features, metrics, buckets, and experiment reports through ae-cli"
5
+ ---
6
+
7
+ # ae-experiment
8
+
9
+ AE CLI (`ae-cli`) exposes Atlas AB Experiment capabilities through the `experiment` domain.
10
+
11
+ ## Global Rules
12
+
13
+ - Prefer `ae-cli experiment <command>` for Atlas AB Experiment work.
14
+ - Use `--project-id` / `-p` for project-scoped commands.
15
+ - Use `--req` JSON for complex save, status, and delete DTOs.
16
+ - Do not invent experiment IDs, traffic layer IDs, bucket IDs, Feature keys, metric IDs, or payload field names.
17
+ - Bind only metric IDs returned by `experiment metric list`; create and verify a missing metric before saving the experiment.
18
+ - Read commands can run directly after IDs are verified.
19
+ - Write commands require explicit user intent and normally keep the confirmation prompt. Use `--dry-run` before write calls when composing JSON.
20
+
21
+ Naming and response boundary:
22
+
23
+ - CLI command segments and flags use kebab-case.
24
+ - Outer Capability input and all response keys use snake_case.
25
+ - Nested business DTOs passed through `--req` keep their native camelCase fields.
26
+ - **CRITICAL:** `save build-guide` / `save validate` responses recursively snake_case
27
+ `example_args.req`. Never copy those keys into `--req`. Use camelCase
28
+ (`expName`, `metricId`, …). Authoritative names:
29
+ `ae-cli capability inspect experiment.experiment.save` (or the matching final save id)
30
+ → `input_schema.properties.req`. `save validate` `valid: true` is **not** a final-save
31
+ schema pass — snake_case `req` can still fail on `experiment … save`.
32
+ - Audience QP is semantic at the CLI boundary: write `targeting.definitionRequest`; read
33
+ `targeting.definition_request`. Never generate or submit `targetConfig`.
34
+ - Metric QP is semantic at the CLI boundary: write `metricDefinition`; read
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.
39
+ - For metric aggregations `sum` / `avg` / `max` / `distinct_count`, `metricDefinition.property`
40
+ is **required** and must be a concrete available event property from Analysis metadata.
41
+ Never create property aggregations without `property` (for example `metric_avg_no_property_*`).
42
+ - Preset event aggregations `total_count` / `user_count` / `active_days` omit `property`.
43
+ - Experiment metric creation does not support `avg_per_user` / `A105`.
44
+ - Resolve event and property names with Analysis metadata before saving semantic definitions.
45
+ - Lists return `data.items` and `data.total`; detail commands return `data.item`.
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`.
47
+ - Query cancellation returns `data.success`.
48
+
49
+ ## Typical Workflow
50
+
51
+ 1. Discover reusable assets:
52
+ - `experiment bucket list`
53
+ - `experiment traffic-layer list`
54
+ - `experiment feature list`
55
+ - `experiment metric list`
56
+ 2. Create missing assets if needed:
57
+ - `experiment save build-guide --operation-mode save_metric` when save validation fails or req shape is unclear
58
+ - `experiment save validate --operation-mode save_metric --req '{...}'` before retrying a failed save
59
+ - `experiment traffic-layer save`
60
+ - `experiment feature save`
61
+ - `experiment metric save`
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.
64
+ 4. Check readiness with `experiment experiment ready-check`.
65
+ 5. For a non-mutex traffic layer, run `experiment experiment conflict-check` before submit (needs `feature_key_list` from context or `experiment get`).
66
+ 6. Move status with `experiment experiment manage`.
67
+ 7. Query reports with `experiment report summary`, `experiment report sample-size`, and `experiment report metric-trend`.
68
+
69
+ If an experiment save returns `error_code: METRIC_NOT_FOUND`, list metrics for the same project. Create and verify the metric before retrying; never retry with another invented ID. Metric deletion returns `error_code: METRIC_IN_USE` while an active experiment binding exists.
70
+
71
+ ## Parameter Conventions
72
+
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.
75
+
76
+ ```bash
77
+ ae-cli experiment experiment get --project-id 1 --exp-id exp_123
78
+ ae-cli experiment experiment save --project-id 1 --req '{"expName":"Demo"}' --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
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
81
+ ```
82
+
83
+ Optional global parameters work as in other domains: `--host`, `--mcp-url`, `--format`, `--jq`, `--dry-run`, and `--yes`.
84
+
85
+ ## References
86
+
87
+ Open the matching file in `references/` before using a command, especially for write operations and JSON payloads.
88
+
89
+ ### Save Helpers
90
+
91
+ `experiment save build-guide`, `experiment save validate`
92
+
93
+ When a save command returns `next_tool: experiment.save.build-guide`, call the guide first, then `experiment save validate`, then retry the final save capability.
94
+
95
+ Read [`save_build_guide.md`](references/save_build_guide.md) and
96
+ [`save_validate.md`](references/save_validate.md) before using these helpers. Rebuild
97
+ `--req` in camelCase from `inspect` / skill references; do not paste `example_args.req`.
98
+
99
+ ### Experiment
100
+
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.
104
+
105
+ ### Traffic Layer and Buckets
106
+
107
+ `experiment traffic-layer save`, `experiment traffic-layer get`, `experiment traffic-layer list`, `experiment traffic-layer batch-delete`, `experiment bucket list`
108
+
109
+ ### Reports
110
+
111
+ `experiment report summary`, `experiment report sample-size`, `experiment report metric-trend`, `capability run experiment.query.cancel`
112
+
113
+ ### Metric and Feature
114
+
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,11 @@
1
+ # experiment experiment batch-delete
2
+
3
+ Batch delete experiments.
4
+
5
+ ```bash
6
+ ae-cli experiment experiment batch-delete --project-id <id> --exp-ids '["exp_1","exp_2"]' [--yes]
7
+ ```
8
+
9
+ Flags:
10
+ - `--project-id`, `-p`: Project ID.
11
+ - `--exp-ids`: Experiment ID list as JSON array.
@@ -0,0 +1,11 @@
1
+ # experiment feature batch-delete
2
+
3
+ Batch delete Features.
4
+
5
+ ```bash
6
+ ae-cli experiment feature batch-delete --project-id <id> --req '<json>' [--yes]
7
+ ```
8
+
9
+ Flags:
10
+ - `--project-id`, `-p`: Project ID.
11
+ - `--req`: Feature delete request JSON object.
@@ -0,0 +1,11 @@
1
+ # experiment traffic-layer batch-delete
2
+
3
+ Batch delete traffic layers.
4
+
5
+ ```bash
6
+ ae-cli experiment traffic-layer batch-delete --project-id <id> --layer-ids '["layer_1","layer_2"]' [--yes]
7
+ ```
8
+
9
+ Flags:
10
+ - `--project-id`, `-p`: Project ID.
11
+ - `--layer-ids`: Traffic layer ID list as JSON array.
@@ -0,0 +1,11 @@
1
+ # capability run experiment.query.cancel
2
+
3
+ Cancel a running experiment report query.
4
+
5
+ ```bash
6
+ ae-cli capability run experiment.query.cancel --input '{"request_id":"<id>"}'
7
+ ```
8
+
9
+ Required input: `request_id`.
10
+
11
+ Response shape: `data.success`.
@@ -0,0 +1,17 @@
1
+ # experiment experiment ready-check
2
+
3
+ Check whether an experiment can enter online status transitions.
4
+
5
+ ```bash
6
+ ae-cli experiment experiment ready-check --project-id <id> --exp-id <expId>
7
+ ```
8
+
9
+ Flags:
10
+ - `--project-id`, `-p`: Project ID.
11
+ - `--exp-id`: Experiment ID.
12
+
13
+ Use this before `experiment experiment manage` moves an experiment to `pending`, `testing`, or `running`.
14
+
15
+ Common `groups` failure: `atlas.service.error.experiment.group.allocation.invalid`. Rule: each `groups[].allocation` must be an **integer**, and **sum = 100 exactly** (for example `34 + 33 + 33 = 100`).
16
+
17
+ Response shape: the readiness result is in `data.readiness`, with recursively snake_case keys.
@@ -0,0 +1,37 @@
1
+ # experiment experiment conflict-check
2
+
3
+ Pre-submit check for cross-layer Feature conflicts on a **non-mutex** traffic layer.
4
+
5
+ Reuse the existing Hermes `trafficLayerConflictCheck` API. Do **not** call this command for mutex traffic layers.
6
+
7
+ ## Workflow
8
+
9
+ 1. Ensure you already have the Feature keys for the current experiment:
10
+ - Editing an existing draft: call `experiment experiment get` and read `feature_key_list`.
11
+ - Creating a new experiment: reuse the Feature keys already chosen in the current workflow.
12
+ 2. Call conflict-check with the selected non-mutex `traffic-layer-id`.
13
+ 3. Interpret the response before `save-submit`:
14
+ - `data.features` non-empty: some Features are not enabled.
15
+ - `data.experiments` non-empty: same Features are active on other traffic layers.
16
+ - both empty: no conflict signal from this check.
17
+
18
+ ```bash
19
+ ae-cli experiment experiment conflict-check \
20
+ --project-id <id> \
21
+ --feature-key-list '["checkout_color"]' \
22
+ --traffic-layer-id <layer-id>
23
+
24
+ ae-cli experiment experiment conflict-check \
25
+ --project-id <id> \
26
+ --feature-key-list '["checkout_color"]' \
27
+ --traffic-layer-id <layer-id> \
28
+ --exp-id <exp-id>
29
+ ```
30
+
31
+ Flags:
32
+ - `--project-id`, `-p`: Project ID.
33
+ - `--feature-key-list`: Required JSON string array of Feature keys selected by the current experiment.
34
+ - `--traffic-layer-id`: Required selected non-mutex traffic layer ID.
35
+ - `--exp-id`: Optional current experiment ID when editing an existing draft (excludes self from conflicts).
36
+
37
+ Response shape: `data.experiments` and `data.features`, with recursively snake_case item keys.
@@ -0,0 +1,13 @@
1
+ # experiment metric delete
2
+
3
+ Delete a metric.
4
+
5
+ ```bash
6
+ ae-cli experiment metric delete --project-id <id> --metric-id <metricId> [--yes]
7
+ ```
8
+
9
+ Flags:
10
+ - `--project-id`, `-p`: Project ID.
11
+ - `--metric-id`: Metric ID.
12
+
13
+ Deletion is rejected with `error_code: METRIC_IN_USE` while the metric has an active experiment binding. Remove the metric from the related experiment before retrying.
@@ -0,0 +1,17 @@
1
+ # experiment experiment manage
2
+
3
+ Manage experiment status.
4
+
5
+ ```bash
6
+ ae-cli experiment experiment manage --project-id <id> --exp-id <expId> --target-status <status> [--remark <text>]
7
+ ```
8
+
9
+ Flags:
10
+ - `--project-id`, `-p`: Project ID.
11
+ - `--exp-id`: Experiment ID.
12
+ - `--target-status`: One of `draft`, `testing`, `pending`, `running`, `paused`, `ended`, `archive`.
13
+ - `--remark`: Optional operation remark.
14
+
15
+ When target status is `pending`, `testing`, or `running`, Hermes performs a ready check before changing status.
16
+
17
+ Response shape: the operation or blocking readiness result is in `data.result`, with object keys recursively converted to snake_case.
@@ -0,0 +1,11 @@
1
+ # experiment feature update-status
2
+
3
+ Update Feature status.
4
+
5
+ ```bash
6
+ ae-cli experiment feature update-status --project-id <id> --req '<json>'
7
+ ```
8
+
9
+ Flags:
10
+ - `--project-id`, `-p`: Project ID.
11
+ - `--req`: Feature status request JSON object.