@qingflow-tech/qingflow-app-user-mcp 1.0.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 (109) hide show
  1. package/README.md +37 -0
  2. package/docs/local-agent-install.md +332 -0
  3. package/entry_point.py +13 -0
  4. package/npm/bin/qingflow-app-user-mcp.mjs +7 -0
  5. package/npm/lib/runtime.mjs +339 -0
  6. package/npm/scripts/postinstall.mjs +16 -0
  7. package/package.json +34 -0
  8. package/pyproject.toml +67 -0
  9. package/qingflow-app-user-mcp +15 -0
  10. package/skills/qingflow-app-user/SKILL.md +79 -0
  11. package/skills/qingflow-app-user/agents/openai.yaml +4 -0
  12. package/skills/qingflow-app-user/references/data-gotchas.md +29 -0
  13. package/skills/qingflow-app-user/references/environments.md +63 -0
  14. package/skills/qingflow-app-user/references/record-patterns.md +48 -0
  15. package/skills/qingflow-app-user/references/workflow-usage.md +26 -0
  16. package/skills/qingflow-record-analysis/SKILL.md +158 -0
  17. package/skills/qingflow-record-analysis/agents/openai.yaml +4 -0
  18. package/skills/qingflow-record-analysis/references/analysis-gotchas.md +145 -0
  19. package/skills/qingflow-record-analysis/references/analysis-patterns.md +125 -0
  20. package/skills/qingflow-record-analysis/references/confidence-reporting.md +92 -0
  21. package/skills/qingflow-record-analysis/references/dsl-templates.md +93 -0
  22. package/skills/qingflow-record-delete/SKILL.md +29 -0
  23. package/skills/qingflow-record-import/SKILL.md +31 -0
  24. package/skills/qingflow-record-insert/SKILL.md +58 -0
  25. package/skills/qingflow-record-update/SKILL.md +42 -0
  26. package/skills/qingflow-task-ops/SKILL.md +123 -0
  27. package/skills/qingflow-task-ops/agents/openai.yaml +4 -0
  28. package/skills/qingflow-task-ops/references/environments.md +44 -0
  29. package/skills/qingflow-task-ops/references/workflow-usage.md +27 -0
  30. package/src/qingflow_mcp/__init__.py +5 -0
  31. package/src/qingflow_mcp/__main__.py +5 -0
  32. package/src/qingflow_mcp/backend_client.py +649 -0
  33. package/src/qingflow_mcp/builder_facade/__init__.py +3 -0
  34. package/src/qingflow_mcp/builder_facade/models.py +1836 -0
  35. package/src/qingflow_mcp/builder_facade/service.py +15044 -0
  36. package/src/qingflow_mcp/cli/__init__.py +1 -0
  37. package/src/qingflow_mcp/cli/commands/__init__.py +18 -0
  38. package/src/qingflow_mcp/cli/commands/app.py +40 -0
  39. package/src/qingflow_mcp/cli/commands/auth.py +44 -0
  40. package/src/qingflow_mcp/cli/commands/builder.py +538 -0
  41. package/src/qingflow_mcp/cli/commands/chart.py +18 -0
  42. package/src/qingflow_mcp/cli/commands/common.py +62 -0
  43. package/src/qingflow_mcp/cli/commands/imports.py +96 -0
  44. package/src/qingflow_mcp/cli/commands/portal.py +25 -0
  45. package/src/qingflow_mcp/cli/commands/record.py +331 -0
  46. package/src/qingflow_mcp/cli/commands/repo.py +80 -0
  47. package/src/qingflow_mcp/cli/commands/task.py +89 -0
  48. package/src/qingflow_mcp/cli/commands/view.py +18 -0
  49. package/src/qingflow_mcp/cli/commands/workspace.py +25 -0
  50. package/src/qingflow_mcp/cli/context.py +60 -0
  51. package/src/qingflow_mcp/cli/formatters.py +334 -0
  52. package/src/qingflow_mcp/cli/json_io.py +50 -0
  53. package/src/qingflow_mcp/cli/main.py +178 -0
  54. package/src/qingflow_mcp/config.py +513 -0
  55. package/src/qingflow_mcp/errors.py +66 -0
  56. package/src/qingflow_mcp/import_store.py +121 -0
  57. package/src/qingflow_mcp/json_types.py +18 -0
  58. package/src/qingflow_mcp/list_type_labels.py +76 -0
  59. package/src/qingflow_mcp/public_surface.py +233 -0
  60. package/src/qingflow_mcp/repository_store.py +71 -0
  61. package/src/qingflow_mcp/response_trim.py +470 -0
  62. package/src/qingflow_mcp/server.py +212 -0
  63. package/src/qingflow_mcp/server_app_builder.py +533 -0
  64. package/src/qingflow_mcp/server_app_user.py +362 -0
  65. package/src/qingflow_mcp/session_store.py +302 -0
  66. package/src/qingflow_mcp/solution/__init__.py +6 -0
  67. package/src/qingflow_mcp/solution/build_assembly_store.py +181 -0
  68. package/src/qingflow_mcp/solution/compiler/__init__.py +282 -0
  69. package/src/qingflow_mcp/solution/compiler/chart_compiler.py +96 -0
  70. package/src/qingflow_mcp/solution/compiler/form_compiler.py +495 -0
  71. package/src/qingflow_mcp/solution/compiler/icon_utils.py +187 -0
  72. package/src/qingflow_mcp/solution/compiler/navigation_compiler.py +57 -0
  73. package/src/qingflow_mcp/solution/compiler/package_compiler.py +19 -0
  74. package/src/qingflow_mcp/solution/compiler/portal_compiler.py +60 -0
  75. package/src/qingflow_mcp/solution/compiler/view_compiler.py +51 -0
  76. package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +173 -0
  77. package/src/qingflow_mcp/solution/design_session.py +222 -0
  78. package/src/qingflow_mcp/solution/design_store.py +100 -0
  79. package/src/qingflow_mcp/solution/executor.py +2398 -0
  80. package/src/qingflow_mcp/solution/normalizer.py +23 -0
  81. package/src/qingflow_mcp/solution/requirements_builder.py +536 -0
  82. package/src/qingflow_mcp/solution/run_store.py +244 -0
  83. package/src/qingflow_mcp/solution/spec_models.py +855 -0
  84. package/src/qingflow_mcp/tools/__init__.py +1 -0
  85. package/src/qingflow_mcp/tools/ai_builder_tools.py +3419 -0
  86. package/src/qingflow_mcp/tools/app_tools.py +925 -0
  87. package/src/qingflow_mcp/tools/approval_tools.py +1062 -0
  88. package/src/qingflow_mcp/tools/auth_tools.py +875 -0
  89. package/src/qingflow_mcp/tools/base.py +388 -0
  90. package/src/qingflow_mcp/tools/code_block_tools.py +777 -0
  91. package/src/qingflow_mcp/tools/custom_button_tools.py +202 -0
  92. package/src/qingflow_mcp/tools/directory_tools.py +675 -0
  93. package/src/qingflow_mcp/tools/feedback_tools.py +238 -0
  94. package/src/qingflow_mcp/tools/file_tools.py +409 -0
  95. package/src/qingflow_mcp/tools/import_tools.py +2189 -0
  96. package/src/qingflow_mcp/tools/navigation_tools.py +210 -0
  97. package/src/qingflow_mcp/tools/package_tools.py +326 -0
  98. package/src/qingflow_mcp/tools/portal_tools.py +158 -0
  99. package/src/qingflow_mcp/tools/qingbi_report_tools.py +374 -0
  100. package/src/qingflow_mcp/tools/record_tools.py +14037 -0
  101. package/src/qingflow_mcp/tools/repository_dev_tools.py +552 -0
  102. package/src/qingflow_mcp/tools/resource_read_tools.py +421 -0
  103. package/src/qingflow_mcp/tools/role_tools.py +112 -0
  104. package/src/qingflow_mcp/tools/solution_tools.py +4054 -0
  105. package/src/qingflow_mcp/tools/task_context_tools.py +2228 -0
  106. package/src/qingflow_mcp/tools/task_tools.py +890 -0
  107. package/src/qingflow_mcp/tools/view_tools.py +335 -0
  108. package/src/qingflow_mcp/tools/workflow_tools.py +376 -0
  109. package/src/qingflow_mcp/tools/workspace_tools.py +125 -0
@@ -0,0 +1,48 @@
1
+ # Record Patterns
2
+
3
+ If the task shifts into grouped analysis, ratio, ranking, trend, or any final statistical conclusion, switch to [$qingflow-record-analysis](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-analysis/SKILL.md).
4
+
5
+ ## Browse Pattern
6
+
7
+ Use `record_browse_schema_get -> record_list` when:
8
+
9
+ - the user wants to browse records
10
+ - the target `record_id` is unknown
11
+ - a delete target still needs confirmation
12
+ - the user needs sample rows or a small export
13
+
14
+ ## Detail Pattern
15
+
16
+ Use `record_browse_schema_get -> record_get` when:
17
+
18
+ - the exact `record_id` is known
19
+ - the user needs one record in detail
20
+ - a write target needs verification before action
21
+
22
+ ## Insert Pattern
23
+
24
+ Use `record_insert_schema_get -> record_insert`.
25
+
26
+ 1. Confirm the target app
27
+ 2. Read `required_fields`, `optional_fields`, `runtime_linked_required_fields`, and `payload_template`
28
+ 3. Build a field-title keyed `fields` map
29
+ 4. If lookup fields are ambiguous, stop and ask for confirmation
30
+ 5. Run `record_insert`
31
+
32
+ ## Update Pattern
33
+
34
+ Use `record_update_schema_get -> record_update`.
35
+
36
+ 1. Confirm the target app and `record_id`
37
+ 2. Read `writable_fields` and `payload_template`
38
+ 3. Update only fields present in `writable_fields`
39
+ 4. Let MCP auto-select the first matched accessible view that can execute the payload
40
+ 5. Run `record_update`
41
+
42
+ ## Delete Pattern
43
+
44
+ Use `record_list / record_get -> record_delete`.
45
+
46
+ 1. Confirm the exact `record_id`
47
+ 2. Run `record_delete`
48
+ 3. Do not invent range deletes from guessed browse results
@@ -0,0 +1,26 @@
1
+ # Workflow and Task Usage Actions
2
+
3
+ Use these when the user is operating inside an existing process, not redesigning it.
4
+
5
+ Examples:
6
+
7
+ - add a comment to a record
8
+ - approve or reject a workflow task
9
+ - transfer a task
10
+ - roll back a task
11
+ - list todo, initiated, done, or cc tasks
12
+ - inspect workload by worksheet or workflow node
13
+ - urge a pending task
14
+
15
+ Rules:
16
+
17
+ - if the user starts from inbox, todo, workload, cc, or bottleneck language, use `task_*` first
18
+ - use `task_summary` for headline counts
19
+ - use `task_list` for flat browsing
20
+ - use `task_facets` when worksheet or workflow-node buckets matter
21
+ - treat task counts as task-center counts, not record counts
22
+ - switch to `record_*` only after locating the exact business record behind a task
23
+ - identify the exact target first
24
+ - for approve or reject, identify the exact `workflow_node_id` first; prefer task-center results or current audit info, then use `task_approve` or `task_reject`
25
+ - avoid usage-side workflow actions on ambiguous records
26
+ - summarize the final action and target task ids or record ids
@@ -0,0 +1,158 @@
1
+ ---
2
+ name: qingflow-record-analysis
3
+ description: Analyze Qingflow record data safely after the MCP is already connected and authenticated. Use when the user wants grouped distributions, ratios, averages, rankings, trends, insights, or any final statistical conclusion across an existing app's data. Do not use this skill for schema changes, app design, or ordinary record CRUD unless they are strictly supporting an analysis flow.
4
+ metadata:
5
+ short-description: Analyze Qingflow record data with schema-first DSL execution
6
+ ---
7
+
8
+ # Qingflow Record Analysis
9
+
10
+ This skill is for final statistical conclusions only.
11
+ Assumes MCP is connected, authenticated, and on the correct workspace.
12
+ Analysis tasks must start with `app_get`, then `record_browse_schema_get(view_id=...)`. Read top-level `fields` and `suggested_*`, then build field_id-based DSLs only.
13
+ Analysis tasks must start with `record_browse_schema_get`.
14
+ If `app_get.accessible_views` marks a view with `analysis_supported=false`, do not use that view for `record_list` or `record_analyze`. `boardView` and `ganttView` are special UI views, not list/analyze targets.
15
+
16
+ ## Step 1: `app_get` → Step 2: `record_browse_schema_get(view_id=...)` → Step 3: build DSL → Step 4: `record_analyze`
17
+
18
+ This is the ONLY execution order. Never skip `app_get` when the browse range is unclear. Never call `record_analyze` without a browse schema.
19
+
20
+ Core tools: `app_get`, `record_browse_schema_get`, `record_analyze`. Use `record_list`/`record_get` only for post-analysis samples; task/comment work stays in [$qingflow-task-ops](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-task-ops/SKILL.md).
21
+
22
+ ---
23
+
24
+ ## DSL Contract
25
+
26
+ ### DSL FORMAT (CRITICAL — read this FIRST)
27
+
28
+ ### ✅ Correct vs ❌ Wrong — learn from these before building ANY DSL
29
+
30
+ **dimension item:**
31
+ ```
32
+ ✅ CORRECT: { "field_id": 9500572, "alias": "报价类型" }
33
+ ❌ WRONG: 9500572 ← bare integer, not a dict
34
+ ❌ WRONG: "报价类型" ← string, not a dict
35
+ ❌ WRONG: { "field_id": 9500572, "title": "报价类型" } ← "title" is forbidden
36
+ ```
37
+
38
+ **metric item — the key is `op`, NOT `type`/`agg`/`aggregation`:**
39
+ ```
40
+ ✅ CORRECT: { "op": "count", "alias": "记录数" }
41
+ ✅ CORRECT: { "op": "sum", "field_id": 7, "alias": "总金额" }
42
+ ❌ WRONG: { "type": "count" } ← "type" is NOT a valid key
43
+ ❌ WRONG: { "agg": "count" } ← "agg" is NOT a valid key
44
+ ❌ WRONG: { "aggregation": "count" } ← "aggregation" is NOT a valid key
45
+ ```
46
+
47
+ **filter item — the key is `op`, NOT `operator`:**
48
+ ```
49
+ ✅ CORRECT: { "field_id": 2, "op": "between", "value": ["2024-03-01", "2024-03-31"] }
50
+ ✅ CORRECT: { "field_id": 5, "op": "eq", "value": "已完成" }
51
+ ❌ WRONG: { "field_id": 2, "operator": "between", "value": [...] } ← "operator" is forbidden
52
+ ❌ WRONG: { "field_id": 2, "op": ">=", "value": "2024-03-01" } ← ">=" is not valid, use "gte"
53
+ ```
54
+
55
+ **sort item:**
56
+ ```
57
+ ✅ CORRECT: { "by": "记录数", "order": "desc" } ← "by" references an alias
58
+ ❌ WRONG: { "by": 9500572, "order": "desc" } ← field_id not allowed in sort
59
+ ```
60
+
61
+ ### Allowed keys per item (ANY other key = error)
62
+
63
+ | Item | Allowed keys only |
64
+ |------|-------------------|
65
+ | dimension | `field_id`, `alias`, `bucket` |
66
+ | metric | `op`, `field_id`, `alias` |
67
+ | filter | `field_id`, `op`, `value` |
68
+ | sort | `by`, `order` |
69
+
70
+ ### `op` values
71
+
72
+ - metrics: `count`, `sum`, `avg`, `min`, `max`, `distinct_count`
73
+ - filters: `eq`, `neq`, `in`, `not_in`, `gt`, `gte`, `lt`, `lte`, `between`, `contains`, `is_null`, `not_null`
74
+ - For `count` metric: do NOT pass `field_id`. For all others: `field_id` is required.
75
+ - If `metrics` is omitted or `[]`, defaults to `[{"op":"count","alias":"记录数"}]`.
76
+
77
+ ---
78
+
79
+ See [references/dsl-templates.md](references/dsl-templates.md) for complete copy-paste templates.
80
+
81
+ **Typical summary / distribution:**
82
+ ```json
83
+ {
84
+ "dimensions": [{ "field_id": FIELD_ID_FROM_SCHEMA, "alias": "维度名" }],
85
+ "metrics": [{ "op": "count", "alias": "记录数" }],
86
+ "sort": [{ "by": "记录数", "order": "desc" }],
87
+ "limit": 50,
88
+ "strict_full": true
89
+ }
90
+ ```
91
+
92
+ **Typical time-filter / trend:**
93
+ ```json
94
+ {
95
+ "dimensions": [{ "field_id": TIME_FIELD_ID, "alias": "月份", "bucket": "month" }],
96
+ "metrics": [{ "op": "count", "alias": "记录数" }],
97
+ "filters": [{ "field_id": TIME_FIELD_ID, "op": "between", "value": ["2024-03-01", "2024-03-31"] }],
98
+ "sort": [{ "by": "月份", "order": "asc" }],
99
+ "limit": 24,
100
+ "strict_full": true
101
+ }
102
+ ```
103
+
104
+ Top-level arguments:
105
+
106
+ - `app_key`: required.
107
+ - `dimensions`: `[]` = whole-table summary; `[{...}]` = grouped.
108
+ - `strict_full`: `true` for final conclusions. `false` allows partial results.
109
+ - `limit`: limits returned rows only, not scan scope.
110
+ - `view_id`: the canonical browse selector. Prefer choosing it from `app_get.accessible_views`.
111
+ - Prefer `view_id` entries where `analysis_supported=true`. If a view is `boardView` or `ganttView`, switch to a system or table-style custom view before calling `record_analyze`.
112
+ - If a chosen `view_id` is `custom:*`, treat the output as analysis over an unverified saved-filter scope unless `verification.view_filter_verified=true`. For critical conclusions, prefer `system:all` plus explicit filters in the DSL.
113
+ - `bucket` in dimensions: only for `suggested_time_fields`. Values: `day`/`week`/`month`/`quarter`/`year`/`null`.
114
+
115
+ ---
116
+
117
+ ## RULES
118
+
119
+ - 渗透率 / 转化率 / 占比类结论必须先定义分子和分母。
120
+ - Do not claim a metric you did not query.
121
+ - Derived ratios must be computed outside the DSL.
122
+ - Before choosing a DSL shape, first decide whether the question needs `count`, `sum`, `avg`, `distinct_count`, `ratio`, or `ranking`.
123
+ - Rankings must come from structured sorted results.
124
+ - For partial answers, explicitly disclose which parts are complete and which parts remain unresolved.
125
+ - Complex answers should default to `先结构、后解读`.
126
+ - `between`: pass a two-item array.
127
+ - Sort entries must reference an alias already defined in `dimensions` or `metrics`.
128
+ - Final wording should stay as close as possible to schema titles.
129
+ - Do not pass field titles, aliases, or guessed ids.
130
+ - If `completeness.statement_scope=returned_groups_only` or `completeness.rows_truncated=true`, downgrade wording to returned groups only.
131
+ - One DSL per question. Multiple small DSLs > one overloaded request.
132
+ - `record_list` is NEVER the basis for final statistics.
133
+ - Set `alias` for any metric you will sort by, compare, or quote.
134
+
135
+ ---
136
+
137
+ ## OUTPUT
138
+
139
+ - Final answer must show concrete numbers.
140
+ - If `result.rows` exists, list each returned row; if there are more than 20 rows, show Top 20 and say so.
141
+ - 占比 = 行指标值 / `result.totals.metric_totals` 总值;如 `metric_totals` 缺失,用各行之和作分母。
142
+ - Prefer the structured `ranking` block when it exists.
143
+ - `safe_for_final_conclusion=true` → `全量可信结论`
144
+ - Otherwise → `初步观察`
145
+ - `rows_truncated=true` → 用 `前 N 个分组`, 不用 `全部`/`所有`
146
+
147
+ ## Feedback Escalation
148
+
149
+ - If the desired analysis still cannot be completed because of missing capability, unsupported analysis shape, or an obviously awkward workflow after reasonable attempts, summarize the exact gap.
150
+ - Ask whether the user wants you to submit product feedback.
151
+ - Only after explicit user confirmation, call `feedback_submit`.
152
+
153
+ ## Resources
154
+
155
+ - DSL templates: [references/dsl-templates.md](references/dsl-templates.md)
156
+ - Analysis patterns: [references/analysis-patterns.md](references/analysis-patterns.md)
157
+ - Confidence reporting: [references/confidence-reporting.md](references/confidence-reporting.md)
158
+ - Analysis gotchas: [references/analysis-gotchas.md](references/analysis-gotchas.md)
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Qingflow Record Analysis"
3
+ short_description: "Analyze Qingflow record data with schema-first DSL execution"
4
+ default_prompt: "Use $qingflow-record-analysis for grouped distributions, ratios, rankings, trends, and final statistical conclusions in Qingflow apps. Start with record_browse_schema_get, build one or more field_id-based DSLs, then run record_analyze. Treat record_list as sample-only when capped or paged, and separate full conclusions from sample observations."
@@ -0,0 +1,145 @@
1
+ # Analysis Gotchas
2
+
3
+ ## Do not skip schema
4
+
5
+ If the task is analysis-style and you jump straight to `record_list` or `record_analyze`, you are already off the stable path.
6
+
7
+ Correct recovery:
8
+
9
+ 1. `record_browse_schema_get`
10
+ 2. inspect the schema and choose fields
11
+ 3. build one or more small DSLs
12
+ 4. run `record_analyze`
13
+
14
+ The schema here is applicant-node visible-only. If a field is absent, treat it as not available to the current user rather than switching to guessed ids or builder-side memory.
15
+
16
+ ## Normalize relative time phrases before building the DSL.
17
+
18
+ Examples:
19
+
20
+ - `最近一个完整自然月` -> convert to an explicit full-month date range
21
+ - `上个月` -> convert to a concrete month range
22
+ - `最近30天` -> convert to exact start/end dates
23
+
24
+ Do not pass vague time phrases or impossible dates into MCP.
25
+
26
+ ## Do not treat 200-row list output as full data
27
+
28
+ `record_list` can hit:
29
+
30
+ - `row_cap=200`
31
+ - `row_cap_hit=true`
32
+ - `sample_only=true`
33
+
34
+ When this happens, it is sample-only evidence.
35
+
36
+ It is not acceptable to use that result alone for:
37
+
38
+ - 平均值
39
+ - 占比
40
+ - 排名
41
+ - 趋势
42
+ - 地域分布
43
+ - “基于全部数据”的 business insight
44
+
45
+ ## Do not mix full analyze totals with sample rows
46
+
47
+ If `record_analyze` gives full-population coverage, but list rows are capped, do not merge them into one final statement.
48
+
49
+ Split them into:
50
+
51
+ - `全量可信结论`
52
+ - `样本观察`
53
+
54
+ ## Do not present truncated grouped rows as a full grouped list
55
+
56
+ If `completeness.rows_truncated=true` or `completeness.statement_scope=returned_groups_only`:
57
+
58
+ - do not say `各部门`
59
+ - do not say `所有分组`
60
+ - do not say `完整名单`
61
+
62
+ Correct recovery:
63
+
64
+ - do not describe the answer as complete grouped coverage
65
+ - keep the wording inside the returned group scope
66
+
67
+ ## Do not guess fields under ambiguity
68
+
69
+ If the field is uncertain:
70
+
71
+ - do not bounce across tools
72
+ - do not guess ids
73
+ - do not switch from one read tool to another by trial and error
74
+ - do not keep retrying different guessed field names in a loop
75
+
76
+ Correct recovery:
77
+
78
+ 1. `record_browse_schema_get`
79
+ 2. if several plausible candidates remain, ask the user to confirm from a short list
80
+ 3. build the DSL only after the field is clear
81
+
82
+ If the intended field is absent from the schema altogether, stop and explain that it is not visible in the current applicant-node permission scope.
83
+
84
+ Examples of the right recovery question:
85
+
86
+ - “我找到两个可能的字段:`线索来源`、`来源渠道`。你要按哪个字段统计?”
87
+ - “目前最像‘来源’的字段有这三个:`来源`、`来源渠道`、`获客来源`。请确认你要按哪个字段分析。”
88
+
89
+ ## Do not try to control paging manually
90
+
91
+ `record_analyze` hides paging and scan budget on purpose.
92
+
93
+ - Do not invent `page_size`
94
+ - Do not invent `requested_pages`
95
+ - Do not invent `scan_max_pages`
96
+ - Do not invent `auto_expand_pages`
97
+
98
+ When the result is incomplete:
99
+
100
+ 1. narrow the scope with views or filters
101
+ 2. reduce the analysis problem into smaller DSLs
102
+ 3. keep the answer at `初步观察` or `部分结果` if completeness is still not enough
103
+
104
+ ## Do not guess metric semantics from loose business wording
105
+
106
+ Before building the DSL, first decide whether the question needs:
107
+
108
+ - `count`
109
+ - `sum`
110
+ - `avg`
111
+ - `distinct_count`
112
+ - a ratio with numerator + denominator
113
+ - a sorted ranking result
114
+
115
+ Do not jump straight from words like `数量`, `人数`, `单量`, or `金额` to one assumed metric.
116
+
117
+ ## Do not hide partial completion
118
+
119
+ If the user asked for several outputs and only part of them is stable:
120
+
121
+ - say which parts are complete
122
+ - say which parts are still unresolved
123
+ - do not present the answer as fully finished
124
+
125
+ ## Do not send unsupported formula or div-style metrics into `record_analyze`.
126
+
127
+ Examples to avoid:
128
+
129
+ - `{"op":"div", ...}`
130
+ - metric items with `formula`, `expr`, `numerator`, or `denominator`
131
+
132
+ Correct recovery:
133
+
134
+ 1. query the source metrics with separate DSLs
135
+ 2. confirm both sides are complete and compatible
136
+ 3. compute the derived ratio outside MCP in the reasoning layer
137
+
138
+ ## Do not call something a ratio without the denominator
139
+
140
+ If the user asks for penetration / conversion / 占比:
141
+
142
+ 1. define numerator
143
+ 2. define denominator
144
+ 3. query both sides explicitly
145
+ 4. only then compute and report the ratio
@@ -0,0 +1,125 @@
1
+ # Analysis Patterns
2
+
3
+ ## When to use this skill
4
+
5
+ Use this skill when the user asks for:
6
+
7
+ - 分布
8
+ - 占比
9
+ - 平均值
10
+ - 排名 / top-N
11
+ - 趋势
12
+ - 洞察
13
+ - 最终统计结论
14
+ - 全量范围内的 business summary
15
+
16
+ ## Canonical analysis sequence
17
+
18
+ 1. `record_browse_schema_get`
19
+ 2. decide whether the question needs `count`, `sum`, `avg`, `distinct_count`, `ratio`, or `ranking`
20
+ 3. build one or more field_id-based DSLs
21
+ 4. `record_analyze`
22
+ 5. `record_list` only for sample inspection
23
+
24
+ Result reading order:
25
+
26
+ 1. `result.rows`
27
+ 2. `result.totals.metric_totals`
28
+ 3. `ranking`
29
+ 4. `ratios`
30
+ 5. `completeness`
31
+ 6. `presentation`
32
+
33
+ Treat `record_browse_schema_get` as the browse-schema source of truth. Missing fields are permission boundaries, not invitations to guess hidden ids.
34
+
35
+ ## Distribution / ratio pattern
36
+
37
+ 1. Run `record_browse_schema_get`
38
+ 2. Inspect candidate fields and aliases
39
+ 3. If several plausible candidates remain, stop and ask the user to confirm the field from a short list
40
+ 4. Build a DSL with:
41
+ - one dimension
42
+ - `count`
43
+ - sort by the count alias
44
+ 5. Run `record_analyze`
45
+ 6. Report:
46
+ - `result.totals.metric_totals`
47
+ - `safe_for_final_conclusion`
48
+ - `completeness.statement_scope`
49
+ - `completeness.warnings`
50
+ 7. If grouped rows are truncated, describe the answer as `主要分组` or `已返回分组中`, not `各部门` or `全部`
51
+
52
+ ## penetration / conversion / share-of-total pattern
53
+
54
+ 1. Run `record_browse_schema_get`
55
+ 2. Write down the business definition in plain language:
56
+ - numerator
57
+ - denominator
58
+ - grouping dimension, if any
59
+ 3. Build separate DSLs when numerator and denominator are not the same filtered population
60
+ 4. Query the numerator first
61
+ 5. Query the denominator second
62
+ 6. Only compute the ratio outside MCP after both source results are complete and use compatible scopes
63
+ 7. If the denominator is missing, do not call the output `渗透率`, `转化率`, `占比`, or `%`
64
+
65
+ ## Average / ranking pattern
66
+
67
+ 1. Run `record_browse_schema_get`
68
+ 2. Choose one dimension field and one numeric metric field
69
+ 3. Build a DSL with:
70
+ - `dimensions=[...]`
71
+ - `metrics=[count,sum]` or `metrics=[count,avg,min,max]`
72
+ 4. Run `record_analyze`
73
+ 5. If the answer uses ranking language, make the ranking come from structured sorted results
74
+ 6. Prefer the structured `ranking` block when it exists instead of inferring order from loose text
75
+ 7. Use list mode only to inspect examples after the aggregate result is understood
76
+
77
+ ## Trend pattern
78
+
79
+ 1. Run `record_browse_schema_get`
80
+ 2. Choose a date/time field from `suggested_time_fields`
81
+ 3. Build a DSL with `bucket=day|week|month|quarter|year`
82
+ 4. Run `record_analyze`
83
+ 5. Treat the result as final only if `safe_for_final_conclusion=true`
84
+ 6. If the user asked for a relative time phrase such as `最近一个完整自然月`, translate it into an explicit legal date range before building the DSL
85
+
86
+ ## Sample inspection pattern
87
+
88
+ Only use `record_list` after schema/analyze when you need:
89
+
90
+ - example rows
91
+ - spot checks
92
+ - representative samples
93
+ - manual inspection of records behind an aggregate bucket
94
+
95
+ Never use list mode alone to justify final averages, shares, rankings, or regional distribution claims.
96
+
97
+ ## Statement-to-query discipline
98
+
99
+ - If you want to say `单量低` or `volume low`, query `count`
100
+ - If you want to say `金额高`, query `sum`
101
+ - If you want to say `客单价高`, query `avg` or trusted `sum + count`
102
+ - If you want to say `增长` or `下降`, query a time bucket
103
+ - If you want to say `渗透率` or `占比`, query both numerator and denominator
104
+ - If you want to say `各部门` / `全部渠道` / `完整名单`, make sure `completeness.statement_scope=full_population` and `completeness.rows_truncated=false`
105
+ - If you want to say `Top N` or `排名`, make sure the result is explicitly sorted and the conclusion follows that returned order
106
+ - If the task is complex, default to `先结构、后解读`
107
+
108
+ ## Ambiguous field recovery
109
+
110
+ If the user asks for something like “来源分布” or “类型占比” and the exact field is unclear:
111
+
112
+ 1. run `record_browse_schema_get`
113
+ 2. inspect titles, aliases, and suggested fields
114
+ 3. if one candidate is clearly dominant, proceed
115
+ 4. if multiple candidates are still plausible, ask the user to confirm which field they want
116
+
117
+ Do not keep retrying different guessed field names in a loop.
118
+
119
+ ## Partial completion discipline
120
+
121
+ If the user asked for several conclusions and only some of them are fully supported:
122
+
123
+ 1. state which parts are complete
124
+ 2. state which parts are still unresolved
125
+ 3. do not present the answer as fully complete
@@ -0,0 +1,92 @@
1
+ # Confidence Reporting
2
+
3
+ ## Required output structure
4
+
5
+ When analysis is intended as a final answer, use this order:
6
+
7
+ 1. `全量可信结论`
8
+ 2. `样本观察`
9
+ 3. `待验证假设`
10
+
11
+ ## Full conclusion gate
12
+
13
+ Only write `全量可信结论` when:
14
+
15
+ - `record_browse_schema_get` was used
16
+ - the analysis path used one or more `record_analyze` calls
17
+ - every key analysis result has `safe_for_final_conclusion=true`
18
+ - `safe_for_final_conclusion=true is necessary but not sufficient`
19
+ - no key result depends on an invalid time phrase, an undefined denominator, or an unsupported derived metric
20
+ - the result is not just a capped list sample
21
+
22
+ ## Sample observation gate
23
+
24
+ Put evidence into `样本观察` when:
25
+
26
+ - it came from `record_list`
27
+ - the tool reports `row_cap_hit`
28
+ - the tool reports `sample_only`
29
+ - the result is compact/capped and not complete
30
+
31
+ ## Downgrade rule
32
+
33
+ If `record_browse_schema_get` was not used for an analysis task, downgrade the overall framing to `初步观察` instead of `洞察` or `结论`.
34
+
35
+ ## Anti-mixing rule
36
+
37
+ Do not combine:
38
+
39
+ - full totals from `record_analyze`
40
+ - sample-only details from `record_list`
41
+
42
+ into one sentence like “基于全部数据分析...”.
43
+
44
+ Instead:
45
+
46
+ - full totals and distributions go into `全量可信结论`
47
+ - illustrative rows go into `样本观察`
48
+
49
+ ## Semantic gate
50
+
51
+ Even when `safe_for_final_conclusion=true`, do not overstate the answer if:
52
+
53
+ - the metric definition is incomplete
54
+ - the denominator was not queried
55
+ - the conclusion mentions trend but no time bucket was queried
56
+ - the conclusion mentions单量/volume but no `count` metric was queried
57
+ - the conclusion depends on a derived metric the DSL cannot natively express
58
+ - `completeness.statement_scope=returned_groups_only`
59
+ - `completeness.rows_truncated=true`
60
+
61
+ ## Grouped enumeration gate
62
+
63
+ If grouped rows were truncated:
64
+
65
+ - do not call the grouped output `各部门`, `全部渠道`, `完整名单`, or `所有分组`
66
+ - use `已返回分组中`, `主要分组`, or `前 N 个分组`
67
+ - keep full-population statements only for metrics that still cover the full analyzed population
68
+
69
+ ## Partial completion disclosure
70
+
71
+ If the user asked for multiple conclusions but only some are complete:
72
+
73
+ - explicitly disclose which parts are complete
74
+ - explicitly disclose which parts are not yet complete
75
+ - do not collapse the answer into one all-clear conclusion
76
+
77
+ ## Example skeleton
78
+
79
+ ### 全量可信结论
80
+
81
+ - `result.totals.metric_totals=...`
82
+ - `safe_for_final_conclusion=true`
83
+ - 这里写最终业务结论
84
+
85
+ ### 样本观察
86
+
87
+ - 以下来自样本明细浏览,不作为最终统计结论
88
+ - 这里写代表性样本现象
89
+
90
+ ### 待验证假设
91
+
92
+ - 这里写还需要进一步验证的推测
@@ -0,0 +1,93 @@
1
+ # DSL Templates
2
+
3
+ Use these copy-paste templates after `record_browse_schema_get`.
4
+
5
+ ## Whole-table summary
6
+
7
+ ```json
8
+ {
9
+ "dimensions": [],
10
+ "metrics": [
11
+ { "op": "count", "alias": "记录数" }
12
+ ],
13
+ "strict_full": true
14
+ }
15
+ ```
16
+
17
+ ## Distribution / ranking
18
+
19
+ ```json
20
+ {
21
+ "dimensions": [
22
+ { "field_id": 9500572, "alias": "报价类型" }
23
+ ],
24
+ "metrics": [
25
+ { "op": "count", "alias": "记录数" }
26
+ ],
27
+ "sort": [
28
+ { "by": "记录数", "order": "desc" }
29
+ ],
30
+ "limit": 50,
31
+ "strict_full": true
32
+ }
33
+ ```
34
+
35
+ ## Time-filtered distribution
36
+
37
+ ```json
38
+ {
39
+ "app_key": "YOUR_APP_KEY",
40
+ "dimensions": [
41
+ { "field_id": 9500572, "alias": "维度名" }
42
+ ],
43
+ "metrics": [
44
+ { "op": "count", "alias": "记录数" }
45
+ ],
46
+ "filters": [
47
+ { "field_id": 3, "op": "between", "value": ["2024-03-01", "2024-03-31"] }
48
+ ],
49
+ "sort": [
50
+ { "by": "记录数", "order": "desc" }
51
+ ],
52
+ "limit": 50,
53
+ "strict_full": true
54
+ }
55
+ ```
56
+
57
+ ## Monthly trend
58
+
59
+ ```json
60
+ {
61
+ "dimensions": [
62
+ { "field_id": 3, "alias": "月份", "bucket": "month" }
63
+ ],
64
+ "metrics": [
65
+ { "op": "count", "alias": "记录数" }
66
+ ],
67
+ "sort": [
68
+ { "by": "月份", "order": "asc" }
69
+ ],
70
+ "limit": 24,
71
+ "strict_full": true
72
+ }
73
+ ```
74
+
75
+ ## Cross analysis with sum
76
+
77
+ ```json
78
+ {
79
+ "dimensions": [
80
+ { "field_id": 2, "alias": "状态" },
81
+ { "field_id": 5, "alias": "负责人" }
82
+ ],
83
+ "metrics": [
84
+ { "op": "count", "alias": "记录数" },
85
+ { "op": "sum", "field_id": 7, "alias": "总金额" }
86
+ ],
87
+ "sort": [
88
+ { "by": "记录数", "order": "desc" }
89
+ ],
90
+ "limit": 100,
91
+ "strict_full": true
92
+ }
93
+ ```