@wubaoqi/guancopilot 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/NOTICE.md +17 -0
  2. package/README.md +146 -2
  3. package/assets/coreutils.wasm +0 -0
  4. package/assets/find.wasm +0 -0
  5. package/assets/guanbi.wasm +4 -0
  6. package/assets/guancli.wasm +0 -0
  7. package/assets/guanhelm.wasm +0 -0
  8. package/assets/jq.wasm +0 -0
  9. package/assets/openskills.wasm +0 -0
  10. package/assets/rg.wasm +0 -0
  11. package/assets/sed.wasm +0 -0
  12. package/bin/guancopilot +0 -0
  13. package/bin/guanvm +0 -0
  14. package/bin/platforms.cjs +6 -0
  15. package/bin/run.cjs +39 -0
  16. package/bin/runtime.cjs +44 -0
  17. package/licenses/Go-LICENSE +27 -0
  18. package/licenses/browser-_speed-highlight_core-LICENSE +121 -0
  19. package/licenses/browser-_speed-highlight_core-package.json +14 -0
  20. package/licenses/browser-dompurify-LICENSE +202 -0
  21. package/licenses/browser-dompurify-LICENSE-MPL +373 -0
  22. package/licenses/browser-dompurify-package.json +10 -0
  23. package/licenses/browser-marked-LICENSE +44 -0
  24. package/licenses/browser-marked-package.json +10 -0
  25. package/licenses/coreutils-LICENSE +18 -0
  26. package/licenses/findutils-LICENSE +18 -0
  27. package/licenses/github.com_BurntSushi_toml_v1.6.0-COPYING +21 -0
  28. package/licenses/github.com_dustin_go-humanize_v1.0.1-LICENSE +21 -0
  29. package/licenses/github.com_google_jsonschema-go_v0.4.3-LICENSE +21 -0
  30. package/licenses/github.com_google_uuid_v1.6.0-LICENSE +27 -0
  31. package/licenses/github.com_jackc_pgpassfile_v1.0.0-LICENSE +22 -0
  32. package/licenses/github.com_jackc_pgservicefile_v0.0.0-20240606120523-5a60cdf6a761-LICENSE +22 -0
  33. package/licenses/github.com_jackc_pgx_v5_v5.11.0-LICENSE +22 -0
  34. package/licenses/github.com_jackc_puddle_v2_v2.2.2-LICENSE +22 -0
  35. package/licenses/github.com_mattn_go-isatty_v0.0.20-LICENSE +9 -0
  36. package/licenses/github.com_modelcontextprotocol_go-sdk_v1.8.0-LICENSE +216 -0
  37. package/licenses/github.com_ncruces_go-strftime_v1.0.0-LICENSE +21 -0
  38. package/licenses/github.com_remyoudompheng_bigfft_v0.0.0-20230129092748-24d4a6f8daec-LICENSE +27 -0
  39. package/licenses/github.com_santhosh-tekuri_jsonschema_v6_v6.0.3-LICENSE +175 -0
  40. package/licenses/github.com_segmentio_asm_v1.1.3-LICENSE +21 -0
  41. package/licenses/github.com_segmentio_encoding_v0.5.4-LICENSE +21 -0
  42. package/licenses/github.com_tetratelabs_wazero_v1.12.0-LICENSE +201 -0
  43. package/licenses/github.com_tetratelabs_wazero_v1.12.0-NOTICE +2 -0
  44. package/licenses/github.com_yosida95_uritemplate_v3_v3.0.2-LICENSE +25 -0
  45. package/licenses/golang.org_x_image_v0.44.0-LICENSE +27 -0
  46. package/licenses/golang.org_x_net_v0.58.0-LICENSE +27 -0
  47. package/licenses/golang.org_x_oauth2_v0.36.0-LICENSE +27 -0
  48. package/licenses/golang.org_x_sync_v0.22.0-LICENSE +27 -0
  49. package/licenses/golang.org_x_sys_v0.47.0-LICENSE +27 -0
  50. package/licenses/golang.org_x_text_v0.41.0-LICENSE +27 -0
  51. package/licenses/golang.org_x_time_v0.15.0-LICENSE +27 -0
  52. package/licenses/guanbi-skills-LICENSE +133 -0
  53. package/licenses/guanbi-skills-LICENSE.README.md +28 -0
  54. package/licenses/guanbi-skills-LICENSE.zh-CN +82 -0
  55. package/licenses/jq-COPYING +176 -0
  56. package/licenses/modernc.org_libc_v1.73.4-LICENSE +27 -0
  57. package/licenses/modernc.org_libc_v1.73.4-LICENSE-3RD-PARTY.md +305 -0
  58. package/licenses/modernc.org_mathutil_v1.7.1-LICENSE +27 -0
  59. package/licenses/modernc.org_memory_v1.11.0-LICENSE +27 -0
  60. package/licenses/modernc.org_memory_v1.11.0-LICENSE-GO +27 -0
  61. package/licenses/modernc.org_memory_v1.11.0-LICENSE-LOGO +1 -0
  62. package/licenses/modernc.org_memory_v1.11.0-LICENSE-MMAP-GO +25 -0
  63. package/licenses/modernc.org_sqlite_v1.53.0-LICENSE +26 -0
  64. package/licenses/mvdan.cc_sh_v3_v3.13.1-LICENSE +27 -0
  65. package/licenses/ripgrep-COPYING +3 -0
  66. package/licenses/ripgrep-LICENSE-MIT +21 -0
  67. package/licenses/sed-LICENSE +21 -0
  68. package/manifest.json +972 -0
  69. package/package.json +30 -4
  70. package/plugin/guancopilot.js +193 -0
  71. package/skills-bundle/.guanvm-skills-bundle +0 -0
  72. package/skills-bundle/_recipes/dashboard/gates/page_check.js +16 -0
  73. package/skills-bundle/_recipes/dashboard/gates/report_check.js +4 -0
  74. package/skills-bundle/_recipes/dashboard/knowledge/01.md +1 -0
  75. package/skills-bundle/_recipes/dashboard/knowledge/02.md +1 -0
  76. package/skills-bundle/_recipes/dashboard/knowledge/03.md +1 -0
  77. package/skills-bundle/_recipes/dashboard/knowledge/04.md +1 -0
  78. package/skills-bundle/_recipes/dashboard/knowledge/05.md +1 -0
  79. package/skills-bundle/_recipes/dashboard/knowledge/06.md +1 -0
  80. package/skills-bundle/_recipes/dashboard/template.json +41 -0
  81. package/skills-bundle/_recipes/etl/gates/etl_live_check.js +10 -0
  82. package/skills-bundle/_recipes/etl/gates/etl_report_check.js +3 -0
  83. package/skills-bundle/_recipes/etl/knowledge/01.md +1 -0
  84. package/skills-bundle/_recipes/etl/knowledge/02.md +9 -0
  85. package/skills-bundle/_recipes/etl/knowledge/03.md +1 -0
  86. package/skills-bundle/_recipes/etl/knowledge/04.md +1 -0
  87. package/skills-bundle/_recipes/etl/knowledge/05.md +1 -0
  88. package/skills-bundle/_recipes/etl/template.json +39 -0
  89. package/skills-bundle/_recipes/hints.json +46 -0
  90. package/skills-bundle/guancli/.commandface.json +155 -0
  91. package/skills-bundle/guancli/SKILL.md +342 -0
  92. package/skills-bundle/guancli/evals/evals.json +156 -0
  93. package/skills-bundle/guancli/evals/fixtures/metric-candidate-empty-search.json +13 -0
  94. package/skills-bundle/guancli/evals/fixtures/metric-candidate-prior-request.json +13 -0
  95. package/skills-bundle/guancli/evals/fixtures/metric-consumption-columns.json +46 -0
  96. package/skills-bundle/guancli/evals/fixtures/metric-consumption-metadata.json +36 -0
  97. package/skills-bundle/guancli/evals/fixtures/metric-consumption-query.json +18 -0
  98. package/skills-bundle/guancli/references/analysis-primitives.md +95 -0
  99. package/skills-bundle/guancli/references/auth-and-config.md +131 -0
  100. package/skills-bundle/guancli/references/examples/metric-date-in.json +7 -0
  101. package/skills-bundle/guancli/references/examples/metric-query-rows.py +83 -0
  102. package/skills-bundle/guancli/references/examples/metric-query.sh +6 -0
  103. package/skills-bundle/guancli/references/form-chatbi.md +199 -0
  104. package/skills-bundle/guancli/references/gateway.md +148 -0
  105. package/skills-bundle/guancli/references/metric-batch-query.md +82 -0
  106. package/skills-bundle/guancli/references/metric-commands.md +562 -0
  107. package/skills-bundle/guancli/references/metric-generic-query.md +215 -0
  108. package/skills-bundle/guancli/references/metric-json-migration.md +18 -0
  109. package/skills-bundle/guancli/references/metric-query-recipes.md +358 -0
  110. package/skills-bundle/guancli/references/preview-and-output.md +192 -0
  111. package/skills-bundle/guancli/references/resource-query.md +101 -0
  112. package/skills-bundle/guands/SKILL.md +281 -0
  113. package/skills-bundle/guands/references/calc-fields-boundaries-and-pitfalls.md +160 -0
  114. package/skills-bundle/guands/references/command-reference.md +267 -0
  115. package/skills-bundle/guands/references/incremental-and-schedule.md +157 -0
  116. package/skills-bundle/guands/references/workflows.md +256 -0
  117. package/skills-bundle/guanetl/SKILL.md +391 -0
  118. package/skills-bundle/guanetl/evals/evals.json +41 -0
  119. package/skills-bundle/guanetl/references/ETL_AI_DEVELOP.md +456 -0
  120. package/skills-bundle/guanmetric/SKILL.md +144 -0
  121. package/skills-bundle/guanmetric/evals/evals.json +117 -0
  122. package/skills-bundle/guanmetric/evals/fixtures/atomic-detail-read-model.json +18 -0
  123. package/skills-bundle/guanmetric/evals/fixtures/confirmed-template-summary.json +12 -0
  124. package/skills-bundle/guanmetric/evals/fixtures/create-result-unknown-state.json +13 -0
  125. package/skills-bundle/guanmetric/evals/forward-eval-2026-09-21.json +62 -0
  126. package/skills-bundle/guanmetric/references/metric-api-contract-examples.json +690 -0
  127. package/skills-bundle/guanmetric/references/metric-api-contract.schema.json +349 -0
  128. package/skills-bundle/guanmetric/references/metric-api-contracts.md +436 -0
  129. package/skills-bundle/guanmetric/references/metric-atomic-mutation.md +238 -0
  130. package/skills-bundle/guanmetric/references/metric-batch-status.md +71 -0
  131. package/skills-bundle/guanmetric/references/metric-business-dictionary-api-contract-examples.json +53 -0
  132. package/skills-bundle/guanmetric/references/metric-business-dictionary-api-contract.schema.json +26 -0
  133. package/skills-bundle/guanmetric/references/metric-business-dictionary.md +76 -0
  134. package/skills-bundle/guanmetric/references/metric-common-fields.md +246 -0
  135. package/skills-bundle/guanmetric/references/metric-composite-mutation.md +165 -0
  136. package/skills-bundle/guanmetric/references/metric-delete-mutation.md +70 -0
  137. package/skills-bundle/guanmetric/references/metric-derived-mutation.md +453 -0
  138. package/skills-bundle/guanmetric/references/metric-excel-template.md +365 -0
  139. package/skills-bundle/guanmetric/references/metric-expression-rules.md +146 -0
  140. package/skills-bundle/guanmetric/references/metric-flow-generate-example.json +79 -0
  141. package/skills-bundle/guanmetric/references/metric-flow-generate.schema.json +93 -0
  142. package/skills-bundle/guanmetric/references/metric-flow.md +218 -0
  143. package/skills-bundle/guanmetric/references/metric-hierarchy-api-contract-examples.json +171 -0
  144. package/skills-bundle/guanmetric/references/metric-hierarchy-api-contract.schema.json +167 -0
  145. package/skills-bundle/guanmetric/references/metric-hierarchy-api-contracts.md +193 -0
  146. package/skills-bundle/guanmetric/references/metric-mutation.md +155 -0
  147. package/skills-bundle/guanmetric/references/metric-public-dimension-api-contract-examples.json +62 -0
  148. package/skills-bundle/guanmetric/references/metric-public-dimension-api-contract.schema.json +47 -0
  149. package/skills-bundle/guanmetric/references/metric-public-dimension.md +155 -0
  150. package/skills-bundle/guanmetric/references/metric-tree-api-contract-examples.json +277 -0
  151. package/skills-bundle/guanmetric/references/metric-tree-api-contract.schema.json +263 -0
  152. package/skills-bundle/guanmetric/references/metric-tree-api-contracts.md +53 -0
  153. package/skills-bundle/guanmetric/references/metric-tree-mutation.md +500 -0
  154. package/skills-bundle/guanmetric/references/metric-validation-ownership.md +74 -0
  155. package/skills-bundle/guanvis/SKILL.md +333 -0
  156. package/skills-bundle/guanvis/evals/china_map/card_01_basic_map.js +13 -0
  157. package/skills-bundle/guanvis/evals/china_map/card_02_world_map.js +10 -0
  158. package/skills-bundle/guanvis/evals/china_map/card_03_point_map.js +12 -0
  159. package/skills-bundle/guanvis/evals/china_map/page.js +10 -0
  160. package/skills-bundle/guanvis/evals/china_map/schema.js +10 -0
  161. package/skills-bundle/guanvis/evals/comparative_mvp_roundtrip/README.md +30 -0
  162. package/skills-bundle/guanvis/evals/comparative_mvp_roundtrip/card_01_comparative_mvp.js +72 -0
  163. package/skills-bundle/guanvis/evals/comparative_mvp_roundtrip/page.js +6 -0
  164. package/skills-bundle/guanvis/evals/comparative_mvp_roundtrip/schema.js +22 -0
  165. package/skills-bundle/guanvis/evals/comparative_mvp_roundtrip/verify_default_roundtrip.sh +92 -0
  166. package/skills-bundle/guanvis/evals/complex_report_pro/card_01_monthly.js +63 -0
  167. package/skills-bundle/guanvis/evals/complex_report_pro/page.js +6 -0
  168. package/skills-bundle/guanvis/evals/complex_report_pro/schema.js +6 -0
  169. package/skills-bundle/guanvis/evals/custom_chart_echarts/card_01_bar.js +13 -0
  170. package/skills-bundle/guanvis/evals/custom_chart_echarts/card_02_pie.js +13 -0
  171. package/skills-bundle/guanvis/evals/custom_chart_echarts/charts/bar.js +11 -0
  172. package/skills-bundle/guanvis/evals/custom_chart_echarts/charts/pie.js +15 -0
  173. package/skills-bundle/guanvis/evals/custom_chart_echarts/page.js +5 -0
  174. package/skills-bundle/guanvis/evals/custom_chart_echarts/schema.js +9 -0
  175. package/skills-bundle/guanvis/evals/custom_chart_sdk/card_01_level_nodes.js +19 -0
  176. package/skills-bundle/guanvis/evals/custom_chart_sdk/charts/level_nodes.css +51 -0
  177. package/skills-bundle/guanvis/evals/custom_chart_sdk/charts/level_nodes.html +1 -0
  178. package/skills-bundle/guanvis/evals/custom_chart_sdk/charts/level_nodes.js +28 -0
  179. package/skills-bundle/guanvis/evals/custom_chart_sdk/page.js +5 -0
  180. package/skills-bundle/guanvis/evals/custom_chart_sdk/schema.js +7 -0
  181. package/skills-bundle/guanvis/evals/dynamic_fields/card_01_dynamic_dataset.js +20 -0
  182. package/skills-bundle/guanvis/evals/dynamic_fields/card_02_dynamic_metric_chart.js +16 -0
  183. package/skills-bundle/guanvis/evals/dynamic_fields/metrics.js +19 -0
  184. package/skills-bundle/guanvis/evals/dynamic_fields/page.js +9 -0
  185. package/skills-bundle/guanvis/evals/dynamic_fields/schema.js +7 -0
  186. package/skills-bundle/guanvis/evals/dynamic_fields/verify_default_roundtrip.sh +137 -0
  187. package/skills-bundle/guanvis/evals/percentage_advcalc_roundtrip/README.md +26 -0
  188. package/skills-bundle/guanvis/evals/percentage_advcalc_roundtrip/card_01_percentage_advcalc.js +44 -0
  189. package/skills-bundle/guanvis/evals/percentage_advcalc_roundtrip/card_02_scroll_percentage.js +12 -0
  190. package/skills-bundle/guanvis/evals/percentage_advcalc_roundtrip/page.js +6 -0
  191. package/skills-bundle/guanvis/evals/percentage_advcalc_roundtrip/schema.js +22 -0
  192. package/skills-bundle/guanvis/evals/rank_advcalc_roundtrip/README.md +28 -0
  193. package/skills-bundle/guanvis/evals/rank_advcalc_roundtrip/card_01_rank_advcalc.js +59 -0
  194. package/skills-bundle/guanvis/evals/rank_advcalc_roundtrip/page.js +6 -0
  195. package/skills-bundle/guanvis/evals/rank_advcalc_roundtrip/schema.js +22 -0
  196. package/skills-bundle/guanvis/evals/rank_advcalc_roundtrip/verify_default_roundtrip.sh +135 -0
  197. package/skills-bundle/guanvis/evals/running_total_advcalc_roundtrip/README.md +15 -0
  198. package/skills-bundle/guanvis/evals/running_total_advcalc_roundtrip/card_01_running_total_advcalc.js +74 -0
  199. package/skills-bundle/guanvis/evals/running_total_advcalc_roundtrip/page.js +6 -0
  200. package/skills-bundle/guanvis/evals/running_total_advcalc_roundtrip/schema.js +22 -0
  201. package/skills-bundle/guanvis/evals/sales_dashboard/card_01_revenue_column.js +10 -0
  202. package/skills-bundle/guanvis/evals/sales_dashboard/card_02_trend_line.js +9 -0
  203. package/skills-bundle/guanvis/evals/sales_dashboard/card_03_kpi.js +6 -0
  204. package/skills-bundle/guanvis/evals/sales_dashboard/card_04_pie.js +9 -0
  205. package/skills-bundle/guanvis/evals/sales_dashboard/card_05_calc_field_test.js +12 -0
  206. package/skills-bundle/guanvis/evals/sales_dashboard/page.js +11 -0
  207. package/skills-bundle/guanvis/evals/sales_dashboard/schema.js +14 -0
  208. package/skills-bundle/guanvis/evals/sales_dashboard/selector_01_region.js +10 -0
  209. package/skills-bundle/guanvis/evals/split_charts/card_01_column_split.js +10 -0
  210. package/skills-bundle/guanvis/evals/split_charts/card_02_line_split.js +10 -0
  211. package/skills-bundle/guanvis/evals/split_charts/card_03_combo_split.js +11 -0
  212. package/skills-bundle/guanvis/evals/split_charts/page.js +10 -0
  213. package/skills-bundle/guanvis/evals/split_charts/schema.js +14 -0
  214. package/skills-bundle/guanvis/evals/tab_layout/card_00_total_revenue.js +6 -0
  215. package/skills-bundle/guanvis/evals/tab_layout/card_01_revenue.js +10 -0
  216. package/skills-bundle/guanvis/evals/tab_layout/card_02_trend.js +9 -0
  217. package/skills-bundle/guanvis/evals/tab_layout/card_03_story.js +11 -0
  218. package/skills-bundle/guanvis/evals/tab_layout/page.js +23 -0
  219. package/skills-bundle/guanvis/evals/tab_layout/schema.js +11 -0
  220. package/skills-bundle/guanvis/evals/tab_layout/selector_01_region.js +8 -0
  221. package/skills-bundle/guanvis/references/api-reference.md +476 -0
  222. package/skills-bundle/guanvis/references/builder-reference.md +1676 -0
  223. package/skills-bundle/guanvis/references/chart-properties.md +2101 -0
  224. package/skills-bundle/guanvis/references/checkout-editing.md +53 -0
  225. package/skills-bundle/guanvis/references/complex-report-pro-patterns.md +398 -0
  226. package/skills-bundle/guanvis/references/dir-and-page-management.md +48 -0
  227. package/skills-bundle/guanvis/references/metric-chart-reference.md +258 -0
  228. package/skills-bundle/guanvis/references/publish-and-constraints.md +60 -0
  229. package/skills-bundle/guanvis/references/selector-reference.md +431 -0
  230. package/skills-bundle/guanvis/references/tableau-migration.md +73 -0
  231. package/skills-bundle/guanvis/references/theme.md +123 -0
  232. package/skills-bundle/guanvis/references/troubleshooting.md +25 -0
  233. package/skills-bundle/guanvis/references/validation-and-chart-patterns.md +205 -0
  234. package/skills-bundle/guanwf/SKILL.md +543 -0
  235. package/skills-bundle/guanwf/references/ETL_AI_DEVELOP.md +456 -0
  236. package/skills-bundle/guanwf/references/TASK_NODE_CONTRACTS.md +64 -0
  237. package/skills-bundle/guanwf/references/WORKFLOW_DSL.md +536 -0
  238. package/skills-bundle/guanwf/references/WORKFLOW_NODES.md +166 -0
  239. package/skills-bundle/js/SKILL.md +145 -0
@@ -0,0 +1,436 @@
1
+ # 指标创建、编辑、详情和列表 API 契约
2
+
3
+ 本文给 Agent 提供可直接参考的真实结构。完整脱敏样例见
4
+ `metric-api-contract-examples.json`,机器可读约束见
5
+ `metric-api-contract.schema.json`。
6
+
7
+ ## 证据与适用范围
8
+
9
+ - 2026-09-21 在 test71 使用 `guancli`/`guanmetric` 做了只读查询和隔离测试资源实测。
10
+ - 复合/衍生专用创建、编辑、影响校验和写后回读已使用账号密码认证实测;本轮未使用 PAT 做有权、无权和资源不存在对照,PAT 兼容性仍标记为未验证。
11
+ - 复合指标和六种衍生配置均完成创建;复合、衍生完成原地编辑、详情回读和列表查询;创建/编辑响应均为 `{result:"ok",response:{id}}`。
12
+ - 原子字段模式和表达式模式的详情结构来自真实指标回读;写请求字段同时对照当前 BI 写 DTO 和 Web 对应语义。
13
+ - test71 当前原子创建接口对非空 `applicableDims` 仍返回 `5001 适用维度无效`,因此本文不把该次失败称为成功实测。请求结构仍是当前后端 DTO 与 CLI 的正式契约;在目标环境提交前必须先 dry-run,并以真实创建和回读为最终结论。
14
+ - 所有样例均已脱敏。字段结构、空值形态和读写差异保留;样例 ID 不能直接拿去调用真实环境。
15
+ - 响应允许后端新增字段。Schema 对响应使用 `additionalProperties: true`,Agent 不应因为出现新字段而拒绝解析。
16
+
17
+ ## 接口矩阵
18
+
19
+ | 操作 | 方法与路径 | 请求 | 成功响应 |
20
+ | --- | --- | --- | --- |
21
+ | 创建原子 | `POST /api/metric-platform/metrics/atomic-metrics` | `CreateAtomicMetricRO` | mutation success |
22
+ | 编辑原子 | `POST /api/metric-platform/metrics/atomic-metrics/{id}` | `UpdateAtomicMetricRO` | mutation success |
23
+ | 创建复合 | `POST /api/metric-platform/metrics/composite-metrics` | `CreateCompositeMetricRO` | mutation success |
24
+ | 编辑复合 | `POST /api/metric-platform/metrics/composite-metrics/{id}` | `UpdateCompositeMetricRO` | mutation success |
25
+ | 创建衍生 | `POST /api/metric-platform/metrics/derived-metrics` | `CreateDerivedMetricRO` | mutation success |
26
+ | 编辑衍生 | `POST /api/metric-platform/metrics/derived-metrics/{id}` | `UpdateDerivedMetricRO` | mutation success |
27
+ | 指标详情 | `GET /api/metric-platform/metrics/{id}` | 无;草稿加 `?fromDraft=true` | detail response |
28
+ | 指标列表 | `POST /api/metric-platform/metrics` | list request | list response |
29
+
30
+ 以上是客户端实际路径。BI 后端路由是去掉 `/api` 后的同路径。写接口分别需要
31
+ `METRIC_PLATFORM` 的 `CREATE` 或 `UPDATE` 权限,详情和列表需要 `READ` 权限。
32
+
33
+ ## 原始响应与 CLI canonical 输出
34
+
35
+ 本文描述的是 `--raw` 或 `guanmetric fetch` 看到的后端原始 envelope:
36
+
37
+ ```json
38
+ {
39
+ "result": "ok",
40
+ "response": {}
41
+ }
42
+ ```
43
+
44
+ `guancli metric get/search -f json` 是供普通机器发现使用的 canonical 输出,外层通常是
45
+ `schemaVersion/command/resultMode/rowCount/data`。canonical 输出会主动省略部分写入字段,
46
+ 例如 `formula`、`formulaField`、`deriveSetting`,所以不能用它重建编辑请求。需要编辑时用
47
+ `--raw` 读取完整详情,再按本文映射成写模型。
48
+
49
+ `guanmetric create/edit` 的人类输出可能只展示解包后的 `{"id":"..."}`;这不改变底层 API
50
+ 响应契约。
51
+
52
+ ## 创建和编辑成功响应
53
+
54
+ 三种指标的创建和编辑共用同一响应:
55
+
56
+ ```json
57
+ {
58
+ "result": "ok",
59
+ "response": {
60
+ "id": "metric_example_id"
61
+ }
62
+ }
63
+ ```
64
+
65
+ 只收到 HTTP 2xx 但 `result` 不是 `ok`,或 `response.id` 缺失,不能认为创建/编辑成功。
66
+ 创建后必须详情回读;上线指标还必须按 `metric-flow.md` 验证状态、权限和查询可用性。
67
+
68
+ ## 创建与编辑的公共字段
69
+
70
+ | 字段 | 创建 | 编辑 | 类型 | 说明 |
71
+ | --- | --- | --- | --- | --- |
72
+ | `projectId` | 必填 | 必填 | string | 指标主题 ID |
73
+ | `subType` | 必填 | 必填 | enum | `ATOMIC/COMPOSITE/DERIVED` |
74
+ | `name` | 必填 | 必填 | string | 指标名称 |
75
+ | `engName` | 可选 | 可选 | string | 英文名 |
76
+ | `desc` | 必填 | 必填 | string | 业务口径 |
77
+ | `format` | 可选 | 可选 | object | 数字格式 |
78
+ | `filter` | 可选 | 可选 | object/null | WebFilterData |
79
+ | `bizAttrs` | 可选 | 可选 | array | 业务属性 `{id,values}` |
80
+ | `dynamicParameters` | 可选 | 可选 | array | 动态参数默认值 |
81
+ | `publish` | 必填 | 必填 | boolean | `false` 草稿,`true` 上线/进入审批 |
82
+ | `bizMetricId` | 可选 | 可选 | string | 关联业务指标 |
83
+ | `parentDirId` | 必填 | 不传 | string | 创建位置;编辑不会通过定义接口移动目录 |
84
+ | `businessOwner` | 必填 | 不传 | string | 创建负责人;详情中变成用户对象 |
85
+
86
+ 编辑接口接收完整更新写模型,不是 JSON Merge Patch。`guanmetric edit` 可以让用户提供 patch,
87
+ 但 CLI 必须先把详情读模型规范化成完整写模型,再合并 patch。
88
+
89
+ ## 原子指标
90
+
91
+ ### 字段来源模式
92
+
93
+ 写模型必须同时提供 `fdId` 和 `aggrType`:
94
+
95
+ ```json
96
+ {
97
+ "projectId": "project_demo",
98
+ "subType": "ATOMIC",
99
+ "dsId": "ds_orders",
100
+ "name": "销售额",
101
+ "fdId": "fd_amount",
102
+ "aggrType": "SUM",
103
+ "applicableDims": ["fd_order_date", "fd_region"],
104
+ "timeDim": "fd_order_date",
105
+ "desc": "订单销售额合计",
106
+ "parentDirId": "dir_demo",
107
+ "businessOwner": "user_owner",
108
+ "publish": false
109
+ }
110
+ ```
111
+
112
+ 详情不返回顶层 `fdId`,而是返回:
113
+
114
+ ```json
115
+ {
116
+ "result": "ok",
117
+ "response": {
118
+ "subType": "ATOMIC",
119
+ "dsInfo": {"dsId": "ds_orders", "name": "订单明细"},
120
+ "fdInfos": [
121
+ {"fdId": "fd_amount", "name": "订单金额", "fdType": "DOUBLE", "metaType": "METRIC"}
122
+ ],
123
+ "aggrType": "SUM",
124
+ "applicableDims": [
125
+ {"fdId": "fd_region", "name": "区域", "fdType": "STRING", "metaType": "DIM"}
126
+ ],
127
+ "timeDim": {"fdId": "fd_order_date", "name": "订单日期", "fdType": "DATE"}
128
+ }
129
+ }
130
+ ```
131
+
132
+ ### 表达式模式
133
+
134
+ 表达式模式只传 `formulaField.fdFormula`,不能再传 `fdId/aggrType`:
135
+
136
+ ```json
137
+ {
138
+ "projectId": "project_demo",
139
+ "subType": "ATOMIC",
140
+ "dsId": "ds_orders",
141
+ "name": "含税销售额",
142
+ "formulaField": {
143
+ "fdFormula": "SUM([fd_amount]) + SUM([fd_tax])"
144
+ },
145
+ "applicableDims": ["fd_order_date", "fd_region"],
146
+ "timeDim": "fd_order_date",
147
+ "desc": "订单金额与税额之和",
148
+ "parentDirId": "dir_demo",
149
+ "businessOwner": "user_owner",
150
+ "publish": false
151
+ }
152
+ ```
153
+
154
+ 真实详情会同时返回表达式和表达式引用的 `fdInfos`:
155
+
156
+ ```json
157
+ {
158
+ "formulaField": {
159
+ "fdFormula": "SUM([fd_amount]) + SUM([fd_tax])",
160
+ "fdType": "DOUBLE"
161
+ },
162
+ "fdInfos": [
163
+ {"fdId": "fd_amount", "name": "订单金额"},
164
+ {"fdId": "fd_tax", "name": "税额"}
165
+ ],
166
+ "aggrType": null
167
+ }
168
+ ```
169
+
170
+ 这里的 `fdInfos` 只是读模型的解析结果,不能把 `fdInfos[0]` 错当成表达式指标的 `fdId`。
171
+ 判断顺序必须是:有非空 `formulaField.fdFormula` 就保留表达式模式;否则才从
172
+ `fdInfos[0].fdId` 恢复字段来源模式。
173
+
174
+ ## 复合指标
175
+
176
+ 请求核心字段:
177
+
178
+ ```json
179
+ {
180
+ "projectId": "project_demo",
181
+ "subType": "COMPOSITE",
182
+ "name": "客单价",
183
+ "formula": "[metric_sales] / [metric_order_count]",
184
+ "useExpressionMetricCommonDims": true,
185
+ "applicableDims": ["fd_order_date", "fd_region"],
186
+ "timeDim": "fd_order_date",
187
+ "desc": "销售额除以订单数",
188
+ "parentDirId": "dir_demo",
189
+ "businessOwner": "user_owner",
190
+ "publish": false
191
+ }
192
+ ```
193
+
194
+ 详情保留 `formula`,并增加 `referencedMetrics`;`applicableDims` 和 `timeDim` 都变成字段对象:
195
+
196
+ ```json
197
+ {
198
+ "formula": "[metric_sales] / [metric_order_count]",
199
+ "referencedMetrics": [
200
+ {
201
+ "id": "metric_sales",
202
+ "name": "销售额",
203
+ "subType": "ATOMIC",
204
+ "status": "PUBLISHED",
205
+ "timeDim": {"fdId": "fd_order_date"}
206
+ }
207
+ ],
208
+ "applicableDims": [
209
+ {"fdId": "fd_region", "name": "区域", "fdType": "STRING", "metaType": "DIM"}
210
+ ],
211
+ "timeDim": {"fdId": "fd_order_date", "name": "订单日期"}
212
+ }
213
+ ```
214
+
215
+ ## 衍生指标
216
+
217
+ 普通衍生请求必须有 `baseMetricId`;组合衍生不传 `baseMetricId`,在
218
+ `deriveSetting.formula` 中引用指标。详情把 `baseMetricId` 展开为 `baseMetric` 对象;组合衍生
219
+ 还返回 `referencedMetrics`。
220
+
221
+ 六种已实测配置如下,完整请求和详情见 examples JSON。
222
+
223
+ ### 对比 `COMPARATIVE`
224
+
225
+ ```json
226
+ {
227
+ "deriveType": "ORDINARY",
228
+ "advType": "COMPARATIVE",
229
+ "advValue": {
230
+ "advType": "COMPARATIVE",
231
+ "dateFdId": "fd_order_date_month",
232
+ "valueType": "VALUE",
233
+ "offset": 1,
234
+ "offsetType": "MONTH",
235
+ "granularity": "MONTH",
236
+ "window": {"offset": 0}
237
+ }
238
+ }
239
+ ```
240
+
241
+ ### 最近 N `RECENT_X`
242
+
243
+ ```json
244
+ {
245
+ "deriveType": "ORDINARY",
246
+ "advType": "RECENT_X",
247
+ "advValue": {
248
+ "advType": "RECENT_X",
249
+ "granularity": "DAY",
250
+ "baselineOffset": [6, 0],
251
+ "baseline": "DATE_RANGE_PARAM_RIGHT",
252
+ "aggrType": "SUM",
253
+ "includeCurrentValue": true
254
+ }
255
+ }
256
+ ```
257
+
258
+ ### 累计 `XTD`
259
+
260
+ ```json
261
+ {
262
+ "deriveType": "ORDINARY",
263
+ "advType": "XTD",
264
+ "advValue": {
265
+ "advType": "XTD",
266
+ "granularity": "MONTH",
267
+ "baseline": "DATE_RANGE_PARAM_RIGHT",
268
+ "includeCurrentValue": true
269
+ }
270
+ }
271
+ ```
272
+
273
+ ### 期末值 `LAST`
274
+
275
+ ```json
276
+ {
277
+ "deriveType": "ORDINARY",
278
+ "advType": "LAST",
279
+ "advValue": {
280
+ "advType": "LAST",
281
+ "dateFdId": "fd_order_date",
282
+ "calculationMode": "LAST_NON_EMPTY"
283
+ }
284
+ }
285
+ ```
286
+
287
+ 部分历史详情没有 `calculationMode`。编辑时应保留详情里的真实值;新建时按用户选择传
288
+ `NATURAL_LAST_DAY` 或 `LAST_NON_EMPTY`,不要从字段名猜测。
289
+
290
+ ### 业务限定 `BIZ_CONDITION`
291
+
292
+ ```json
293
+ {
294
+ "deriveSetting": {
295
+ "deriveType": "ORDINARY",
296
+ "advType": "BIZ_CONDITION",
297
+ "advValue": {"advType": "BIZ_CONDITION"}
298
+ },
299
+ "filter": {
300
+ "type": "condition",
301
+ "value": {
302
+ "dsId": "ds_orders",
303
+ "fdId": "fd_region",
304
+ "name": "区域",
305
+ "fdType": "STRING",
306
+ "metaType": "DIM",
307
+ "filterType": "IN",
308
+ "filterValue": ["华东"]
309
+ }
310
+ }
311
+ }
312
+ ```
313
+
314
+ 真实回读会补 `filter.not=false`。筛选字段必须属于基础指标的 `applicableDims`。
315
+
316
+ ### 组合衍生 `deriveType=COMPOSITE`
317
+
318
+ ```json
319
+ {
320
+ "deriveType": "COMPOSITE",
321
+ "formula": "[metric_sales_recent_7d] + [metric_sales_mtd]"
322
+ }
323
+ ```
324
+
325
+ ## 详情公共结构
326
+
327
+ 三类详情至少包含下面的公共语义;字段是否出现受类型、状态、权限和版本影响:
328
+
329
+ | 字段 | 类型 | 说明 |
330
+ | --- | --- | --- |
331
+ | `id` | string | 指标 ID |
332
+ | `projectId/projectName` | string | 主题 |
333
+ | `parentDirId/dirPath` | string/array | 所属目录 |
334
+ | `subType` | enum | 也可能读到只读类型 `SHORTCUT` |
335
+ | `uniformResourceType` | string | `METRIC_ATOMIC/COMPOSITE/DERIVED` 等 |
336
+ | `status` | string | 常见 `PUBLISHED/UNPUBLISHED` |
337
+ | `name/engName/desc` | string | 基础属性 |
338
+ | `businessOwner/creator` | object | 用户读模型,不是写请求中的用户 ID |
339
+ | `applicableDims` | field[] | 字段对象数组,不是 ID 数组 |
340
+ | `timeDim` | field/null | 字段对象,不是 ID |
341
+ | `format/filter/bizAttrs` | object/array/null | 可选定义 |
342
+ | `canManage/canUse` | boolean | 当前用户权限 |
343
+ | `hasDraft` | boolean/null | 草稿标识,部分衍生详情可能缺失或为 null |
344
+ | `statisticsData` | object | 引用、浏览统计,只读 |
345
+ | `metricChartConfig` | object | 图表配置,只读 |
346
+ | `ctime/utime` | string | 时间,只读 |
347
+
348
+ `SHORTCUT` 可能出现在列表和详情,但当前 skill 没有它的创建/编辑契约;遇到时只能读取,
349
+ 不要伪造写请求。
350
+
351
+ ## 列表请求与响应
352
+
353
+ 列表接口是 POST,请求示例:
354
+
355
+ ```json
356
+ {
357
+ "projectId": "project_demo",
358
+ "dirId": "dir_demo",
359
+ "status": "PUBLISHED",
360
+ "nameLike": "销售",
361
+ "subTypes": "ATOMIC,COMPOSITE,DERIVED",
362
+ "orderBy": "UTIME_DESC",
363
+ "offset": 0,
364
+ "limit": 20
365
+ }
366
+ ```
367
+
368
+ 关键点:`subTypes` 是逗号分隔字符串,不是数组。`creator`、`businessOwner` 才是字符串数组。
369
+ 分页启用时 `limit` 最大 100。
370
+
371
+ 真实响应外形:
372
+
373
+ ```json
374
+ {
375
+ "result": "ok",
376
+ "response": {
377
+ "contents": [
378
+ {
379
+ "id": "metric_atomic_sales",
380
+ "projectId": "project_demo",
381
+ "status": "PUBLISHED",
382
+ "subType": "ATOMIC",
383
+ "name": "销售额",
384
+ "desc": "订单销售额合计",
385
+ "dirId": "dir_demo",
386
+ "businessOwner": {"uId": "user_owner", "name": "指标负责人"},
387
+ "creator": {"uId": "user_creator", "name": "创建人"},
388
+ "canManage": true,
389
+ "canUse": true,
390
+ "timeDim": {"fdId": "fd_order_date"},
391
+ "hasDraft": false,
392
+ "favorite": false,
393
+ "approvalStatus": null
394
+ }
395
+ ],
396
+ "count": 1,
397
+ "dirPath": [{"dirId": "dir_demo", "dirName": "销售指标"}]
398
+ }
399
+ }
400
+ ```
401
+
402
+ 不同查询路径/版本可能同时返回 `limit/returnedCount`,也可能返回 `dirPath`。解析器应要求
403
+ `contents/count`,其余作为可选字段。
404
+
405
+ ## 读模型到更新写模型映射
406
+
407
+ | 详情读模型 | 更新写模型 | 规则 |
408
+ | --- | --- | --- |
409
+ | `dsInfo.dsId` | `dsId` | 原子指标 |
410
+ | `fdInfos[0].fdId` | `fdId` | 仅字段来源模式 |
411
+ | `aggrType` | `aggrType` | 与 `fdId` 同时存在 |
412
+ | `formulaField.fdFormula` | `formulaField.fdFormula` | 表达式模式优先,丢弃读模型 `fdType` |
413
+ | `applicableDims[].fdId` | `applicableDims[]` | 对象数组压成 ID 数组 |
414
+ | `timeDim.fdId` | `timeDim` | 对象压成 ID;null/缺失则不传 |
415
+ | `businessOwner.uId` | 无 | 更新 DTO 不接收负责人 |
416
+ | `baseMetric.id` | `baseMetricId` | 普通衍生;组合衍生不传 |
417
+ | `formula` | `formula` | 复合指标原样保留 |
418
+ | `deriveSetting` | `deriveSetting` | 深拷贝并保留变体字段 |
419
+ | `filter/format/bizAttrs` | 同名字段 | 保留业务定义 |
420
+
421
+ 必须剔除只读键,包括但不限于:`id`、`domId`、`projectName`、`parentDirId`、`dirPath`、
422
+ `businessOwner`、`creator`、`ctime`、`utime`、`canManage`、`canUse`、`statisticsData`、
423
+ `hasDraft`、`metricChartConfig`、`uniformResourceType`、`sourceDsIds`、`publicDimensionMap`、
424
+ `referencedMetrics`、`baseMetric`、`fdInfos`、`dsInfo`、`isLastSupported`。
425
+
426
+ 不要维护“详情减掉若干字段后直接提交”的黑名单算法;正确做法是按对应 Update DTO 白名单显式构造。
427
+
428
+ ## Agent 使用顺序
429
+
430
+ 1. 先判断 `subType` 和具体模式/衍生变体。
431
+ 2. 从 examples JSON 取同类型样例,只替换业务值和真实 ID。
432
+ 3. 用 schema 检查字段类型,并按类型文档做业务校验。
433
+ 4. 创建/编辑先 dry-run;编辑必须详情回读后显式构造更新写模型。
434
+ 5. 提交后要求 `result=ok` 且 `response.id` 非空。
435
+ 6. 用详情回读验证定义;列表只用于发现和汇总,不能替代详情。
436
+ 7. 要求“可用”时继续执行 `metric-flow.md` 的状态、权限和查询验收。
@@ -0,0 +1,238 @@
1
+ # 原子指标创建与编辑
2
+
3
+ 原子指标用于在单个数据集字段或数据集字段表达式上定义指标口径,例如“订购金额 = SUM(订单金额)”。
4
+
5
+ 创建/编辑请求、真实详情响应和读写映射见 `metric-api-contracts.md`;机器样例见
6
+ `metric-api-contract-examples.json`。不要根据详情响应猜测写模型。
7
+
8
+ ## 触发场景
9
+
10
+ - 用户说“创建原子指标”“基于数据集建指标”“用某个字段求和/计数/平均”。
11
+ - 用户给出数据集、字段、聚合方式。
12
+ - 用户要编辑一个 `subType=ATOMIC` 的指标。
13
+
14
+ ## 创建必填信息
15
+
16
+ | 字段 | 中文 | 说明 |
17
+ | --- | --- | --- |
18
+ | `projectId` | 主题 ID | 指标所属主题 |
19
+ | `subType` | 指标类型 | 固定 `ATOMIC` |
20
+ | `dsId` | 数据集 ID | 指标来源数据集 |
21
+ | `name` | 指标名称 | 最长 50 |
22
+ | `desc` | 业务口径 | 最长 1000 |
23
+ | `applicableDims` | 适用维度 | 数据集字段 ID 数组,不能为空 |
24
+ | `parentDirId` | 保存至/所属文件夹 | 指标目录 ID |
25
+ | `businessOwner` | 责任人 | 用户 ID |
26
+ | `publish` | 保存方式 | `true` 上线,`false` 草稿 |
27
+
28
+ 计算方式二选一:
29
+
30
+ | 模式 | 必填字段 | 说明 |
31
+ | --- | --- | --- |
32
+ | 来源字段 + 聚合方式 | `fdId` + `aggrType` | 最常见;标准 Excel 填 `来源字段` 和 `聚合方式`;来源字段是数据集字段 ID |
33
+ | 表达式 | `formulaField.fdFormula` | 标准 Excel 填 `字段表达式`;例如 `SUM([fd_amount]) + SUM([fd_tax])`;不要同时传 `fdId/aggrType`;支持范围见 `metric-expression-rules.md` |
34
+
35
+ ## 原子专属可选字段
36
+
37
+ | 字段 | 中文 | 说明 |
38
+ | --- | --- | --- |
39
+ | `timeDim` | 时间维度 | 如果适用维度中包含时间字段,优先让用户指定一个时间维度字段 ID |
40
+ | `sourceMetricId` | 来源指标 ID | 复制/快捷等高级场景才传 |
41
+
42
+ 通用可选字段见 `metric-common-fields.md`。
43
+
44
+ ## 聚合方式
45
+
46
+ | `aggrType` | 中文 |
47
+ | --- | --- |
48
+ | `SUM` | 求和 |
49
+ | `MIN` | 最小值 |
50
+ | `MAX` | 最大值 |
51
+ | `AVG` | 平均值 |
52
+ | `CNT` | 计数 |
53
+ | `CNT_DISTINCT` | 去重计数 |
54
+ | `NUL` | 无处理 |
55
+
56
+ 字段判断:
57
+
58
+ - 用户只给字段中文名时,先用 `guancli ds get <dsId> --brief` 查字段和 `fdId`。
59
+ - 来源字段是维度字段时,常用计数、去重计数、最大值、最小值、无处理。
60
+ - 来源字段是指标/数值字段时,常用求和、平均值、最大值、最小值、计数、去重计数。
61
+
62
+ ## 表达式限制
63
+
64
+ 当用户选择“使用表达式”时,先读取 `metric-expression-rules.md`。默认只生成当前前后端明确支持的聚合表达式形态:
65
+
66
+ - `SUM([fd_id])`、`COUNT([fd_id])`
67
+ - 多个聚合项加减:`SUM([fd_a]) - SUM([fd_b])`
68
+ - 条件聚合:`SUM(CASE WHEN ... THEN ... ELSE ... END)`
69
+
70
+ 不要把 `AVG/MAX/MIN/FIRST/LAST/ANY_VALUE` 主动写进 `formulaField.fdFormula`;如果用户要平均值、最大值、最小值,优先走“来源字段 + `aggrType`”。表达式中字段必须写 `[fdId]`,不要提交字段中文名。
71
+
72
+ ### 计算表达式确认
73
+
74
+ 遇到计算表达式时,不要直接替用户决定创建原子表达式还是复合指标。先说明两种方案并询问:
75
+
76
+ - 原子表达式:直接在当前数据集字段上生成 `formulaField.fdFormula`。
77
+ - 复合指标:先创建或复用表达式中的基础原子指标,再用 `[metricId]` 公式创建复合指标。
78
+
79
+ 用户选择复合指标后,再拆解基础度量。例如 `SUM([attributed_sales_fd]) / SUM([spend_amount_fd])` 可先创建或复用“归因销售额”“广告花费”两个原子指标,再创建复合指标:
80
+
81
+ ```text
82
+ [metric_attributed_sales] / [metric_ad_spend]
83
+ ```
84
+
85
+ 用户选择原子表达式,或明确要求“数据集字段表达式原子指标”时,才使用 `formulaField.fdFormula`。
86
+
87
+ ## 信息收集
88
+
89
+ 如果用户只说“帮我创建一个原子指标”,先收集:
90
+
91
+ 1. 指标主题和保存目录。
92
+ 2. 来源数据集和来源字段。
93
+ 3. 计算方式:来源字段 + 聚合方式,还是表达式;如果是表达式,先询问用户是否改用复合指标。用户选择原子表达式时,再按 `metric-expression-rules.md` 校验支持形态。
94
+ 4. 指标名称、业务口径、适用维度、时间维度、是否保存并上线。
95
+ 5. 数据格式:默认、数值、货币、百分比;如需指定,确认小数位、千分位、货币符号/前后缀、数量级单位、百分比是否除以 100。
96
+ 6. 责任人是否用当前登录用户。
97
+ 7. 指标业务属性中启用且必填的 `bizAttrs`。
98
+
99
+ ## JSON 模板:字段聚合
100
+
101
+ ```json
102
+ {
103
+ "projectId": "<metric_project_id>",
104
+ "subType": "ATOMIC",
105
+ "dsId": "<ds_id>",
106
+ "name": "订购金额",
107
+ "engName": "order_amount",
108
+ "fdId": "<source_fd_id>",
109
+ "aggrType": "SUM",
110
+ "applicableDims": ["<dim_fd_id_1>", "<dim_fd_id_2>"],
111
+ "timeDim": "<time_dim_fd_id>",
112
+ "format": {
113
+ "formatType": "CURRENCY",
114
+ "decimalPlaces": 2,
115
+ "useThousandsSeparator": true,
116
+ "prefix": "¥",
117
+ "prefixUnit": null,
118
+ "showPrefixUnit": true,
119
+ "suffix": ""
120
+ },
121
+ "desc": "统计订单明细中的订购金额总和,用于分析销售规模。",
122
+ "parentDirId": "<metric_dir_id>",
123
+ "businessOwner": "<user_id>",
124
+ "publish": false
125
+ }
126
+ ```
127
+
128
+ 没有时间维度时删除 `timeDim`;没有英文名称时删除 `engName`;未指定数据格式时删除 `format` 或传 `{}`。
129
+
130
+ ## JSON 模板:表达式
131
+
132
+ ```json
133
+ {
134
+ "projectId": "<metric_project_id>",
135
+ "subType": "ATOMIC",
136
+ "dsId": "<ds_id>",
137
+ "name": "含税销售额",
138
+ "formulaField": {
139
+ "fdFormula": "SUM([fd_amount]) + SUM([fd_tax])"
140
+ },
141
+ "applicableDims": ["<dim_fd_id_1>", "<dim_fd_id_2>"],
142
+ "format": {
143
+ "formatType": "NUMBER",
144
+ "decimalPlaces": 2,
145
+ "useThousandsSeparator": true,
146
+ "prefixUnit": null,
147
+ "showPrefixUnit": true,
148
+ "prefix": "",
149
+ "suffix": ""
150
+ },
151
+ "desc": "销售金额与税额之和。",
152
+ "parentDirId": "<metric_dir_id>",
153
+ "businessOwner": "<user_id>",
154
+ "publish": false
155
+ }
156
+ ```
157
+
158
+ ## 创建步骤
159
+
160
+ 1. 先输出指标创建计划,按 `metric-mutation.md` 的“指标创建计划”要求展示环境、主题、目录、来源数据集/字段、聚合方式或表达式、适用维度/时间维度、格式、业务属性和保存方式。
161
+ 2. 用户确认计划后,生成 `/tmp/atomic_metric.json`。
162
+ 3. 先 dry-run:
163
+
164
+ ```bash
165
+ guanmetric create --file /tmp/atomic_metric.json --dry-run
166
+ ```
167
+
168
+ 4. 按 `metric-common-fields.md` 向用户摘要并确认。
169
+ 5. 如果 `publish=true`,先跑 save-precheck:
170
+
171
+ ```bash
172
+ guanmetric fetch POST /api/metric-platform/metrics/atomic-metrics/save-precheck --stdin < /tmp/atomic_metric.json
173
+ ```
174
+
175
+ 6. 如果返回 `conflicts` 且非空,展示冲突指标、冲突口径、适用维度差异,等待用户二次确认。
176
+ 7. 校验通过或二次确认后提交:
177
+
178
+ ```bash
179
+ guanmetric create --file /tmp/atomic_metric.json -f json
180
+ ```
181
+
182
+ 8. 响应返回指标 ID 后回读:
183
+
184
+ ```bash
185
+ guancli metric get <metric_id> --brief
186
+ ```
187
+
188
+ ## 编辑步骤
189
+
190
+ 编辑原子指标时复用 Web 顺序:必要时先口径冲突校验,再影响校验,最后提交。
191
+
192
+ 默认编辑模式接收 patch。CLI 会先读取指标详情,将详情读模型规范化为更新写模型(例如
193
+ `fdInfos[0].fdId -> fdId`、维度对象数组 -> 字段 ID 数组),剔除只读字段,再合并 patch。
194
+ 提交前必须仍保留一种完整取数方式:`fdId + aggrType` 或
195
+ `formulaField.fdFormula`。无法安全恢复取数字段时直接拒绝提交,不能用缺少取数方式的请求继续保存。
196
+
197
+ 原子指标 `edit --replace` 已停用。编辑必须提交 patch,由命令优先读取草稿详情;仅当详情接口以结构化业务状态明确表示草稿不存在时才回退正式详情,再按 Update DTO 白名单构造完整请求。不得把 `guancli metric get --raw` 的详情响应直接回写。
198
+ patch 本身也受同一 Update DTO 白名单约束:`id/status/fdInfos/canUse` 等读模型字段会在读取详情和发请求前被拒绝,`subType` 不能改成非 `ATOMIC`。当 filter 只给出 `fdId` 时,规范化必须使用本次实际选中的草稿或正式详情中的 `applicableDims` 元数据,不能重新读取正式版本覆盖草稿上下文。
199
+
200
+ 1. 读取当前详情:
201
+
202
+ ```bash
203
+ guancli metric get <metric_id> --raw
204
+ ```
205
+
206
+ 2. 生成 patch 或完整 payload,先 dry-run:
207
+
208
+ ```bash
209
+ guanmetric edit <metric_id> --file /tmp/atomic_metric_update.json --dry-run
210
+ ```
211
+
212
+ 3. 如果 `publish=true`,调用 save-precheck。编辑态请求体需要带 `metricId`:
213
+
214
+ ```bash
215
+ guanmetric fetch POST /api/metric-platform/metrics/atomic-metrics/save-precheck --stdin < /tmp/atomic_metric_update_precheck.json
216
+ ```
217
+
218
+ 其中 precheck JSON 等于编辑 payload 加:
219
+
220
+ ```json
221
+ { "metricId": "<metric_id>" }
222
+ ```
223
+
224
+ 4. 如果存在 `conflicts`,展示后等待二次确认。
225
+ 5. 调用编辑影响校验:
226
+
227
+ ```bash
228
+ guanmetric fetch POST /api/metric-platform/metrics/atomic-metrics/<metric_id>/validate-update-impact --stdin < /tmp/atomic_metric_update.json
229
+ ```
230
+
231
+ 6. 如果返回 `hasChanged=true` 且 `affectedMetrics` 或 `affectedCards` 非空,展示影响并等待二次确认。
232
+ 7. 提交真实编辑:
233
+
234
+ ```bash
235
+ guanmetric edit <metric_id> --file /tmp/atomic_metric_update.json -f json
236
+ ```
237
+
238
+ 编辑载荷和公式/格式复制使用 `--raw` 的后端详情,成功后从后端 `response` 读取字段;不能把后端响应当成 canonical envelope。普通机器发现使用 `-f json` 并从 `data` 取值,canonical 详情不承诺完整编辑字段。