@josephyan/qingflow-app-user-mcp 1.0.8 → 1.1.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 (88) hide show
  1. package/README.md +6 -2
  2. package/npm/bin/qingflow-app-user-mcp.mjs +31 -2
  3. package/npm/lib/runtime.mjs +43 -2
  4. package/package.json +1 -1
  5. package/pyproject.toml +2 -1
  6. package/skills/qingflow-app-builder/SKILL.md +276 -0
  7. package/skills/qingflow-app-builder/agents/openai.yaml +4 -0
  8. package/skills/qingflow-app-builder/references/build-complete-system.md +428 -0
  9. package/skills/qingflow-app-builder/references/build-single-app.md +530 -0
  10. package/skills/qingflow-app-builder/references/create-app.md +149 -0
  11. package/skills/qingflow-app-builder/references/environments.md +63 -0
  12. package/skills/qingflow-app-builder/references/flow-actors-and-permissions.md +123 -0
  13. package/skills/qingflow-app-builder/references/gotchas.md +108 -0
  14. package/skills/qingflow-app-builder/references/match-rules.md +114 -0
  15. package/skills/qingflow-app-builder/references/public-surface-sync.md +75 -0
  16. package/skills/qingflow-app-builder/references/solution-playbooks.md +52 -0
  17. package/skills/qingflow-app-builder/references/tool-selection.md +107 -0
  18. package/skills/qingflow-app-builder/references/update-flow.md +186 -0
  19. package/skills/qingflow-app-builder/references/update-layout.md +68 -0
  20. package/skills/qingflow-app-builder/references/update-schema.md +72 -0
  21. package/skills/qingflow-app-builder/references/update-views.md +291 -0
  22. package/skills/qingflow-app-builder-code-integrations/SKILL.md +137 -0
  23. package/skills/qingflow-app-builder-code-integrations/agents/openai.yaml +4 -0
  24. package/skills/qingflow-app-builder-code-integrations/references/code-block.md +66 -0
  25. package/skills/qingflow-app-builder-code-integrations/references/q-linker.md +77 -0
  26. package/skills/qingflow-app-user/SKILL.md +2 -1
  27. package/skills/qingflow-app-user/references/data-gotchas.md +5 -3
  28. package/skills/qingflow-app-user/references/public-surface-sync.md +6 -3
  29. package/skills/qingflow-app-user/references/record-patterns.md +14 -4
  30. package/skills/qingflow-mcp-setup/SKILL.md +111 -0
  31. package/skills/qingflow-mcp-setup/agents/openai.yaml +4 -0
  32. package/skills/qingflow-mcp-setup/references/claude-desktop.md +34 -0
  33. package/skills/qingflow-mcp-setup/references/environments.md +61 -0
  34. package/skills/qingflow-mcp-setup/references/generic-stdio.md +31 -0
  35. package/skills/qingflow-mcp-setup/scripts/check_local_server.sh +38 -0
  36. package/skills/qingflow-record-analysis/SKILL.md +94 -183
  37. package/skills/qingflow-record-analysis/agents/openai.yaml +2 -2
  38. package/skills/qingflow-record-analysis/references/analysis-gotchas.md +54 -111
  39. package/skills/qingflow-record-analysis/references/analysis-patterns.md +96 -131
  40. package/skills/qingflow-record-analysis/references/business-context.md +74 -0
  41. package/skills/qingflow-record-analysis/references/confidence-reporting.md +49 -74
  42. package/skills/qingflow-record-analysis/references/data-access-playbook.md +106 -0
  43. package/skills/qingflow-record-analysis/references/pandas-recipes.md +172 -0
  44. package/skills/qingflow-record-analysis/references/report-format.md +76 -0
  45. package/skills/qingflow-record-insert/SKILL.md +28 -7
  46. package/skills/qingflow-record-update/SKILL.md +3 -1
  47. package/skills/qingflow-workflow-builder/SKILL.md +96 -0
  48. package/skills/qingflow-workflow-builder/manifest.yaml +8 -0
  49. package/skills/qingflow-workflow-builder/references/01-overview.md +45 -0
  50. package/skills/qingflow-workflow-builder/references/02-update-mode.md +53 -0
  51. package/skills/qingflow-workflow-builder/references/03-flow-patterns.md +57 -0
  52. package/skills/qingflow-workflow-builder/references/04-stage1-business-modeling.md +131 -0
  53. package/skills/qingflow-workflow-builder/references/05-stage2-members-roles.md +29 -0
  54. package/skills/qingflow-workflow-builder/references/06-stage3-build-spec.md +165 -0
  55. package/skills/qingflow-workflow-builder/references/07-stage4-validate-spec.md +33 -0
  56. package/skills/qingflow-workflow-builder/references/08-stage5-apply-verify.md +51 -0
  57. package/skills/qingflow-workflow-builder/references/09-stage6-summary.md +88 -0
  58. package/skills/qingflow-workflow-builder/references/10-node-config-reference.md +93 -0
  59. package/skills/qingflow-workflow-builder/references/11-troubleshooting.md +15 -0
  60. package/skills/qingflow-workflow-builder/scripts/diff_flow_spec.py +275 -0
  61. package/skills/qingflow-workflow-builder/scripts/validate_flow_spec.py +605 -0
  62. package/src/qingflow_mcp/__init__.py +1 -1
  63. package/src/qingflow_mcp/backend_client.py +55 -1
  64. package/src/qingflow_mcp/builder_facade/models.py +532 -48
  65. package/src/qingflow_mcp/builder_facade/service.py +9194 -2384
  66. package/src/qingflow_mcp/builder_facade/workflow_spec.py +111 -0
  67. package/src/qingflow_mcp/cli/commands/app.py +3 -16
  68. package/src/qingflow_mcp/cli/commands/builder.py +354 -56
  69. package/src/qingflow_mcp/cli/commands/record.py +112 -6
  70. package/src/qingflow_mcp/cli/formatters.py +133 -2
  71. package/src/qingflow_mcp/cli/main.py +204 -3
  72. package/src/qingflow_mcp/public_surface.py +12 -9
  73. package/src/qingflow_mcp/response_trim.py +288 -22
  74. package/src/qingflow_mcp/server.py +29 -20
  75. package/src/qingflow_mcp/server_app_builder.py +108 -30
  76. package/src/qingflow_mcp/server_app_user.py +29 -23
  77. package/src/qingflow_mcp/solution/compiler/__init__.py +1 -3
  78. package/src/qingflow_mcp/solution/compiler/icon_utils.py +294 -0
  79. package/src/qingflow_mcp/solution/executor.py +3 -133
  80. package/src/qingflow_mcp/tools/ai_builder_tools.py +2617 -440
  81. package/src/qingflow_mcp/tools/app_tools.py +53 -8
  82. package/src/qingflow_mcp/tools/package_tools.py +16 -2
  83. package/src/qingflow_mcp/tools/record_tools.py +14451 -9110
  84. package/src/qingflow_mcp/tools/resource_read_tools.py +3 -0
  85. package/src/qingflow_mcp/tools/solution_tools.py +30 -2
  86. package/src/qingflow_mcp/tools/workflow_tools.py +3 -31
  87. package/skills/qingflow-record-analysis/references/dsl-templates.md +0 -93
  88. package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +0 -173
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
+ ROOT="${QINGFLOW_MCP_ROOT:-}"
6
+
7
+ if [[ -z "$ROOT" ]]; then
8
+ if git_root="$(git rev-parse --show-toplevel 2>/dev/null)" && [[ -d "$git_root/qingflow-support/mcp-server" ]]; then
9
+ ROOT="$git_root/qingflow-support/mcp-server"
10
+ elif [[ -d "$PWD/qingflow-support/mcp-server" ]]; then
11
+ ROOT="$PWD/qingflow-support/mcp-server"
12
+ else
13
+ repo_root="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
14
+ if [[ -d "$repo_root/qingflow-support/mcp-server" ]]; then
15
+ ROOT="$repo_root/qingflow-support/mcp-server"
16
+ fi
17
+ fi
18
+ fi
19
+
20
+ if [[ -z "$ROOT" ]]; then
21
+ echo "Unable to locate qingflow-support/mcp-server. Set QINGFLOW_MCP_ROOT to the repo copy of the MCP server." >&2
22
+ exit 1
23
+ fi
24
+
25
+ ENTRY="$ROOT/qingflow-mcp"
26
+ PY="$ROOT/.venv/bin/python"
27
+
28
+ echo "ROOT=$ROOT"
29
+ test -d "$ROOT"
30
+ echo "OK root exists"
31
+
32
+ test -x "$ENTRY"
33
+ echo "OK entrypoint exists and is executable"
34
+
35
+ test -x "$PY"
36
+ echo "OK virtualenv python exists"
37
+
38
+ PYTHONPATH="$ROOT/src" "$PY" -c "import qingflow_mcp.server; print('OK import qingflow_mcp.server')"
@@ -1,67 +1,71 @@
1
1
  ---
2
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.
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, comparisons, or any final statistical conclusion across an existing app's data. Default to schema-first record_access CSV retrieval plus local Python/pandas; do not use export tools unless the user explicitly asks for a file download.
4
4
  metadata:
5
- short-description: Analyze Qingflow record data with schema-first CSV access and Python
5
+ short-description: Analyze Qingflow record data with record_access CSV and Python
6
6
  ---
7
7
 
8
8
  # Qingflow Record Analysis
9
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=...)`. `record_browse_schema_get.fields` is the selected Qingflow table view's readable header schema and is the same field source used by `record_access.fields` / `schema.json`. Read top-level `fields` and `suggested_*`, then choose field_id-based columns and filters only.
13
- If `app_get.accessible_views` marks a view with `analysis_supported=false`, do not use that view for `record_access`, `record_list`, or `record_analyze`. `boardView` and `ganttView` are special UI views, not data-access targets.
10
+ Use this skill only for final statistical conclusions: counts, distributions, ratios, averages, rankings, trends, comparisons, and analysis reports.
14
11
 
15
- ## Step 1: `app_get` → Step 2: `record_browse_schema_get(view_id=...)` → Step 3: `record_access` → Step 4: Python
12
+ Default path, every time:
16
13
 
17
- This is the default execution order. Never skip `app_get` when the browse range is unclear. Never call `record_access` without a browse schema.
18
-
19
- Core tools: `app_get`, `record_browse_schema_get`, `record_access`, Python. Use field_id-based DSLs only for columns, filters, sort clauses, and any optional lightweight `record_analyze` helper. Use `record_list`/`record_get` only for browse samples. Use `record_analyze` only as a lightweight non-default statistics helper when a compact grouped result is enough. Task/comment work stays in [$qingflow-task-ops](../qingflow-task-ops/SKILL.md).
20
-
21
- ## Execution Modes
22
-
23
- Choose the lightest mode that can still support a trustworthy conclusion:
24
-
25
- 1. `client_python_from_record_access`
26
- - Default and preferred path
27
- - Use `record_access` directly after `app_get -> record_browse_schema_get`
28
- - Read CSV shard files from `files[].local_path` with Python
29
- - Treat `complete=true` and `safe_for_final_conclusion=true` as required before giving a full-scope final conclusion
30
-
31
- 2. `lightweight_record_analyze`
32
- - Optional helper for small grouped summaries or quick sanity checks
33
- - Still requires `app_get -> record_browse_schema_get` first
34
- - Do not make this the default agent path
35
-
36
- 3. `cross_app_manual_reconcile`
37
- - Use when the question depends on joining multiple apps, organization-history alias mapping, or other business logic that current public tools do not express directly
38
- - Be explicit that the conclusion is based on manual reconciliation rules, not one single app's CSV access
39
-
40
- ## Fallback Ladder
41
-
42
- Trigger a fallback when any of these are true:
43
-
44
- - `record_access` returns `complete=false`, `truncated=true`, or `safe_for_final_conclusion=false`
45
- - the target view is unsupported for data access
46
- - field semantics are ambiguous enough that local aggregation would be misleading
47
- - the question requires cross-app reconciliation
48
- - the question depends on organization-tree scope, historical department aliases, or other business rules that are not first-class MCP filters
49
-
50
- When you fall back:
51
-
52
- 1. Keep the standard read order: `app_get -> record_browse_schema_get`
53
- 2. State which fallback mode you chose
54
- 3. State whether the result is still full-scope or only a verified subset
55
- 4. State the time field, organization scope, and any alias mapping used
56
- 5. Prefer concrete numbers plus a conservative conclusion over broad wording
57
-
58
- ---
14
+ ```text
15
+ app_get -> record_browse_schema_get(view_id=...) -> record_access -> Python/pandas -> final answer
16
+ ```
59
17
 
60
- ## DSL Contract
18
+ `record_access` may appear either as an MCP tool or as a CLI subcommand. If the active client does not expose an MCP `record_access` tool, do not switch to aggregate helpers. Use the CLI entry instead:
61
19
 
62
- ### `record_access` Contract
20
+ ```bash
21
+ qingflow record --help
22
+ qingflow record access --help
23
+ qingflow record access --app-key APP_KEY --view-id VIEW_ID --columns-file columns.json --where-file where.json --order-by-file order_by.json --json
24
+ ```
63
25
 
64
- Use `record_access` to fetch detail rows into local CSV shards. It does not analyze, aggregate, or return large `items`.
26
+ The CLI command is under the `record` command group, so the discovery path is: first inspect `qingflow record --help`, then inspect `qingflow record access --help`.
27
+
28
+ ## Hard Rules
29
+
30
+ - Never start analysis from `record_list`, export, QingBI, or guessed field ids.
31
+ - Never conclude `record_access` is unavailable just because it is not visible as a top-level MCP tool; check the CLI path `qingflow record access`.
32
+ - Never call `record_access` before `record_browse_schema_get`.
33
+ - Use only field ids returned by `record_browse_schema_get.fields`.
34
+ - If `app_get.accessible_views[].analysis_supported=false`, do not use that view for `record_access`.
35
+ - Prefer an explicit time range or business filter. If the user gives none and the table may be large, ask for scope or use a clearly provided month/quarter/year.
36
+ - Read every CSV shard in `record_access.files[].local_path` with Python. Do not print raw CSV or load raw rows into model context.
37
+ - Before final analysis, run a field-quality profile in pandas: row count, null rate, distinct count, and period coverage for candidate grouping fields.
38
+ - Do not use a high-missing field as the main conclusion dimension. If a candidate dimension is sparse, downgrade it to an `已填写样本观察` and choose a cleaner semantic fallback when available.
39
+ - Full final conclusions require `record_access.complete=true` and `record_access.safe_for_final_conclusion=true`.
40
+ - `record_list` is only for sample inspection after the aggregate result is understood.
41
+ - `record_get` is only for single-record detail verification, logs, references, images, or readable attachments. Read images from `media_assets.items[].local_path`; read documents/tables from `file_assets.items[].local_path` and `extraction.text_path`.
42
+ - `record_export_direct` is only for explicit export/download/Excel requests.
43
+ - `chart_get` / QingBI is only for user-provided report URLs or chart ids.
44
+
45
+ ## Tool Selection
46
+
47
+ | Need | Tool |
48
+ |---|---|
49
+ | Batch analysis, statistics, comparison, report | `record_access -> Python` |
50
+ | Browse a few example rows | `record_list` |
51
+ | Inspect one record, logs, references, images, attachments | `record_get` |
52
+ | User asks to export/download/Excel | `record_export_direct` |
53
+ | User gives report URL or chart id | `chart_get` |
54
+ | Todo/workflow task actions | `$qingflow-task-ops` |
55
+
56
+ ## Standard Procedure
57
+
58
+ 1. Run `app_get` and choose a table-style `view_id` from `accessible_views`.
59
+ 2. Run `record_browse_schema_get(app_key, view_id)`.
60
+ 3. Decide metric intent before fetching data: `count`, `sum`, `avg`, `distinct_count`, ratio, ranking, trend, or comparison.
61
+ 4. Choose minimal `record_access.columns`, plus `where` and `order_by`.
62
+ 5. Run `record_access` through MCP if visible, otherwise through `qingflow record access`.
63
+ 6. Read all returned CSV files in Python; use `fields[]` only when field-id metadata is needed.
64
+ 7. Run field-quality checks for all candidate dimensions.
65
+ 8. Compute results in pandas.
66
+ 9. Report numbers with scope, field choices, field-quality caveats, completeness, and business assumptions.
67
+
68
+ Use field-id DSLs only:
65
69
 
66
70
  ```json
67
71
  {
@@ -73,154 +77,61 @@ Use `record_access` to fetch detail rows into local CSV shards. It does not anal
73
77
  }
74
78
  ```
75
79
 
76
- Then run Python against every `files[].local_path`. CSV columns are stable: `record_id`, then `field_<field_id>`. Use `fields[]` plus `metadata_files.schema` / `metadata_files.readme` in the same output directory to map titles and types, especially when reusing the CSV later.
77
-
78
- - Never ask for `page`, `page_size`, `limit`, or `max_rows`; `record_access` owns paging internally and follows the backend's native paging capability.
79
- - Never treat backend `searchQueIds` as column selection; it is only a full-text search scope.
80
- - If multiple CSV files are returned, read them all.
81
- - If `complete=false` or `safe_for_final_conclusion=false`, downgrade the answer and disclose the limitation.
82
- - `record_export_direct` is only for explicit export/download/Excel requests, not default analysis.
83
- - QingBI/report reads are only for user-provided report URLs or `chart_id`; do not create or use reports as the default analysis path.
84
-
85
- ### `record_analyze` Lightweight DSL
80
+ Never pass `page`, `page_size`, `limit`, `max_rows`, `timeout`, or `profile` to `record_access`.
86
81
 
87
- ### DSL FORMAT (CRITICAL read this FIRST)
82
+ CSV columns are already readable and field-id anchored, for example `项目状态__field_343283094`. Do not expect separate `schema.json` or `README.md` files.
88
83
 
89
- ### Correct vs Wrong learn from these before building ANY DSL
84
+ For CLI use, write JSON argument files instead of embedding large JSON in shell text:
90
85
 
91
- **dimension item:**
92
- ```
93
- ✅ CORRECT: { "field_id": 9500572, "alias": "报价类型" }
94
- WRONG: 9500572 ← bare integer, not a dict
95
- WRONG: "报价类型" ← string, not a dict
96
- ❌ WRONG: { "field_id": 9500572, "title": "报价类型" } "title" is forbidden
86
+ ```bash
87
+ qingflow record access \
88
+ --app-key APP_KEY \
89
+ --view-id system:all \
90
+ --columns-file columns.json \
91
+ --where-file where.json \
92
+ --order-by-file order_by.json \
93
+ --json
97
94
  ```
98
95
 
99
- **metric item — the key is `op`, NOT `type`/`agg`/`aggregation`:**
100
- ```
101
- ✅ CORRECT: { "op": "count", "alias": "记录数" }
102
- ✅ CORRECT: { "op": "sum", "field_id": 7, "alias": "总金额" }
103
- ❌ WRONG: { "type": "count" } ← "type" is NOT a valid key
104
- ❌ WRONG: { "agg": "count" } ← "agg" is NOT a valid key
105
- ❌ WRONG: { "aggregation": "count" } ← "aggregation" is NOT a valid key
106
- ```
96
+ ## Status Handling
107
97
 
108
- **filter item the key is `op`, NOT `operator`:**
109
- ```
110
- ✅ CORRECT: { "field_id": 2, "op": "between", "value": ["2024-03-01", "2024-03-31"] }
111
- ✅ CORRECT: { "field_id": 5, "op": "eq", "value": "已完成" }
112
- ❌ WRONG: { "field_id": 2, "operator": "between", "value": [...] } ← "operator" is forbidden
113
- ❌ WRONG: { "field_id": 2, "op": ">=", "value": "2024-03-01" } ← ">=" is not valid, use "gte"
114
- ```
98
+ Read `record_access.status` before reading files or writing conclusions.
115
99
 
116
- **sort item:**
117
- ```
118
- CORRECT: { "by": "记录数", "order": "desc" } ← "by" references an alias
119
- WRONG: { "by": 9500572, "order": "desc" } ← field_id not allowed in sort
120
- ```
100
+ - `status=success`, `complete=true`, `safe_for_final_conclusion=true`: full-scope answer is allowed.
101
+ - `status=needs_scope`: no CSV was written. Ask for a time/business range or retry with a user-provided period using `scope.suggested_time_fields`.
102
+ - `status=partial`: read returned files only as a subset. Do not give a full-population conclusion.
103
+ - `complete=false`, `truncated=true`, or `safe_for_final_conclusion=false`: answer as `初步观察` or ask for a narrower scope.
121
104
 
122
- ### Allowed keys per item (ANY other key = error)
105
+ ## Business Context
123
106
 
124
- | Item | Allowed keys only |
125
- |------|-------------------|
126
- | dimension | `field_id`, `alias`, `bucket` |
127
- | metric | `op`, `field_id`, `alias` |
128
- | filter | `field_id`, `op`, `value` |
129
- | sort | `by`, `order` |
107
+ If the question mentions department, team, region, owner group, stage, product line, or a named business scope, check whether aliases or child scopes matter before concluding. Use explicit mappings provided by the user or local context; otherwise ask a short clarification.
130
108
 
131
- ### `op` values
109
+ Example: if `烈焰组` and `飓风组` are sub-departments of `北斗部门`, apply that mapping in Python and state it in the answer.
132
110
 
133
- - metrics: `count`, `sum`, `avg`, `min`, `max`, `distinct_count`
134
- - filters: `eq`, `neq`, `in`, `not_in`, `gt`, `gte`, `lt`, `lte`, `between`, `contains`, `is_null`, `not_null`
135
- - For `count` metric: do NOT pass `field_id`. For all others: `field_id` is required.
136
- - If `metrics` is omitted or `[]`, defaults to `[{"op":"count","alias":"记录数"}]`.
111
+ ## Output Shape
137
112
 
138
- ---
113
+ Default to:
139
114
 
140
- See [references/dsl-templates.md](references/dsl-templates.md) for complete copy-paste templates.
115
+ 1. `结论`
116
+ 2. `关键数据`
117
+ 3. `口径与范围`
118
+ 4. `可信度 / 限制`
141
119
 
142
- **Typical summary / distribution:**
143
- ```json
144
- {
145
- "dimensions": [{ "field_id": FIELD_ID_FROM_SCHEMA, "alias": "维度名" }],
146
- "metrics": [{ "op": "count", "alias": "记录数" }],
147
- "sort": [{ "by": "记录数", "order": "desc" }],
148
- "limit": 50,
149
- "strict_full": true
150
- }
151
- ```
120
+ Concrete numbers are mandatory. Ratios require both numerator and denominator. Trends require a time field and explicit date range. Rankings must come from a sorted pandas result.
121
+ If a requested dimension has poor quality, say so explicitly and provide the nearest reliable fallback dimension, for example platform or product instead of a mostly empty module field.
152
122
 
153
- **Typical time-filter / trend:**
154
- ```json
155
- {
156
- "dimensions": [{ "field_id": TIME_FIELD_ID, "alias": "月份", "bucket": "month" }],
157
- "metrics": [{ "op": "count", "alias": "记录数" }],
158
- "filters": [{ "field_id": TIME_FIELD_ID, "op": "between", "value": ["2024-03-01", "2024-03-31"] }],
159
- "sort": [{ "by": "月份", "order": "asc" }],
160
- "limit": 24,
161
- "strict_full": true
162
- }
163
- ```
123
+ ## References
164
124
 
165
- Top-level arguments:
125
+ Load only what is needed:
166
126
 
167
- - `app_key`: required.
168
- - `dimensions`: `[]` = whole-table summary; `[{...}]` = grouped.
169
- - `strict_full`: `true` for final conclusions. `false` allows partial results.
170
- - `limit`: limits returned rows only, not scan scope.
171
- - `view_id`: the canonical browse selector. Prefer choosing it from `app_get.accessible_views`.
172
- - 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_access` or `record_analyze`.
173
- - 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.
174
- - `bucket` in dimensions: only for `suggested_time_fields`. Values: `day`/`week`/`month`/`quarter`/`year`/`null`.
175
-
176
- ---
177
-
178
- ## RULES
179
-
180
- - 渗透率 / 转化率 / 占比类结论必须先定义分子和分母。
181
- - Do not claim a metric you did not query.
182
- - Derived ratios must be computed outside the DSL.
183
- - Before choosing a DSL shape, first decide whether the question needs `count`, `sum`, `avg`, `distinct_count`, `ratio`, or `ranking`.
184
- - Rankings must come from structured sorted results.
185
- - For partial answers, explicitly disclose which parts are complete and which parts remain unresolved.
186
- - Complex answers should default to `先结构、后解读`.
187
- - `between`: pass a two-item array.
188
- - Sort entries must reference an alias already defined in `dimensions` or `metrics`.
189
- - Final wording should stay as close as possible to schema titles.
190
- - Do not pass field titles, aliases, or guessed ids.
191
- - If `completeness.statement_scope=returned_groups_only` or `completeness.rows_truncated=true`, downgrade wording to returned groups only.
192
- - One data-access request per coherent dataset. Multiple small Python computations over the same CSV files are fine.
193
- - `record_list` is not the basis for final statistics. Use it only for browse/sample inspection and disclose that scope if quoted.
194
- - Set `alias` for any metric you will sort by, compare, or quote.
195
-
196
- ---
197
-
198
- ## OUTPUT
199
-
200
- - Final answer must show concrete numbers.
201
- - Final answer must state which execution mode was used whenever the answer is not the default `client_python_from_record_access`
202
- - If `result.rows` exists, list each returned row; if there are more than 20 rows, show Top 20 and say so.
203
- - 占比 = 行指标值 / `result.totals.metric_totals` 总值;如 `metric_totals` 缺失,用各行之和作分母。
204
- - Prefer the structured `ranking` block when it exists.
205
- - `safe_for_final_conclusion=true` → `全量可信结论`
206
- - Otherwise → `初步观察`
207
- - `rows_truncated=true` → 用 `前 N 个分组`, 不用 `全部`/`所有`
208
- - If you used a fallback mode or `record_access.safe_for_final_conclusion=false`, explicitly disclose:
209
- - whether this is full-scope or a manually curated subset
210
- - which time field was used
211
- - which organization scope was used
212
- - whether any historical department aliases or cross-app joins were applied
127
+ - Data access status machine: [references/data-access-playbook.md](references/data-access-playbook.md)
128
+ - Python/pandas templates: [references/pandas-recipes.md](references/pandas-recipes.md)
129
+ - Analysis patterns: [references/analysis-patterns.md](references/analysis-patterns.md)
130
+ - Business mappings and scope: [references/business-context.md](references/business-context.md)
131
+ - Confidence and final wording: [references/confidence-reporting.md](references/confidence-reporting.md)
132
+ - Common mistakes: [references/analysis-gotchas.md](references/analysis-gotchas.md)
133
+ - Report templates: [references/report-format.md](references/report-format.md)
213
134
 
214
135
  ## Feedback Escalation
215
136
 
216
- - 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.
217
- - Ask whether the user wants you to submit product feedback.
218
- - Only after explicit user confirmation, call `feedback_submit`.
219
-
220
- ## Resources
221
-
222
- - Shared public-surface baseline: [public-surface-sync.md](../qingflow-app-user/references/public-surface-sync.md)
223
- - DSL templates: [references/dsl-templates.md](references/dsl-templates.md)
224
- - Analysis patterns: [references/analysis-patterns.md](references/analysis-patterns.md)
225
- - Confidence reporting: [references/confidence-reporting.md](references/confidence-reporting.md)
226
- - Analysis gotchas: [references/analysis-gotchas.md](references/analysis-gotchas.md)
137
+ If the desired analysis cannot be completed because of missing capability, unsupported data shape, or an awkward workflow after reasonable attempts, summarize the exact gap and ask whether to submit product feedback. Only after explicit user confirmation, call `feedback_submit`.
@@ -1,4 +1,4 @@
1
1
  interface:
2
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 app_get and record_browse_schema_get, run record_access with field_id-based columns/where/order_by, then analyze the returned CSV shard files with Python. Treat record_list as sample-only and record_analyze as a lightweight non-default helper."
3
+ short_description: "Analyze Qingflow record data with record_access CSV and Python"
4
+ default_prompt: "Use $qingflow-record-analysis for grouped distributions, ratios, rankings, trends, and final statistical conclusions in Qingflow apps. Start with app_get and record_browse_schema_get, run record_access with field_id-based columns/where/order_by, then analyze every returned CSV shard with Python. Always run field-quality checks before choosing final grouping dimensions, and downgrade sparse dimensions to filled-sample observations. If record_access is not visible as an MCP tool, discover and use the CLI path qingflow record --help -> qingflow record access --help. Treat record_list as sample-only."
@@ -1,148 +1,91 @@
1
1
  # Analysis Gotchas
2
2
 
3
- ## Do not skip schema
3
+ ## Do Not Skip Schema
4
4
 
5
- If the task is analysis-style and you jump straight to `record_list`, `record_export_direct`, or `record_analyze`, you are already off the stable path.
6
-
7
- Correct recovery:
5
+ Correct path:
8
6
 
9
7
  1. `app_get`
10
8
  2. `record_browse_schema_get`
11
- 3. inspect the schema and choose fields
12
- 4. run `record_access`
13
- 5. use Python over the returned CSV shards
14
-
15
- 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.
16
-
17
- ## Normalize relative time phrases before building the DSL.
18
-
19
- Examples:
20
-
21
- - `最近一个完整自然月` -> convert to an explicit full-month date range
22
- - `上个月` -> convert to a concrete month range
23
- - `最近30天` -> convert to exact start/end dates
24
-
25
- Do not pass vague time phrases or impossible dates into MCP.
26
-
27
- ## Do not treat paged list output as full data
28
-
29
- `record_list` can hit:
30
-
31
- - `row_cap=200`
32
- - `row_cap_hit=true`
33
- - `sample_only=true`
34
-
35
- When this happens, it is sample-only evidence.
36
-
37
- It is not acceptable to use that result alone for:
9
+ 3. `record_access`
10
+ 4. Python
38
11
 
39
- - 平均值
40
- - 占比
41
- - 排名
42
- - 趋势
43
- - 地域分布
44
- - “基于全部数据”的 business insight
12
+ `record_browse_schema_get` returns readable fields for the selected view. Missing fields are permission or view-scope boundaries, not invitations to guess hidden ids.
45
13
 
46
- ## Do not mix full analyze totals with sample rows
14
+ ## Do Not Use Export For Analysis
47
15
 
48
- If `record_access` or `record_analyze` gives full-population coverage, but list rows are capped, do not merge them into one final statement.
16
+ Export tools are for user-requested files. Analysis uses `record_access` because it returns structured completeness and compact field metadata.
49
17
 
50
- Split them into:
18
+ ## Do Not Treat `record_list` As Full Data
51
19
 
52
- - `全量可信结论`
53
- - `样本观察`
20
+ `record_list` is sample/browse only. It can be capped and should not justify:
54
21
 
55
- ## Do not present truncated grouped rows as a full grouped list
22
+ - average
23
+ - share
24
+ - ranking
25
+ - trend
26
+ - regional distribution
27
+ - "all data" insights
56
28
 
57
- If `completeness.rows_truncated=true` or `completeness.statement_scope=returned_groups_only`:
29
+ ## Do Not Control Paging
58
30
 
59
- - do not say `各部门`
60
- - do not say `所有分组`
61
- - do not say `完整名单`
31
+ `record_access` owns paging internally.
62
32
 
63
- Correct recovery:
33
+ Do not invent:
64
34
 
65
- - do not describe the answer as complete grouped coverage
66
- - keep the wording inside the returned group scope
35
+ - `page`
36
+ - `page_size`
37
+ - `limit`
38
+ - `requested_pages`
39
+ - `scan_max_pages`
40
+ - `max_rows`
41
+ - `timeout`
67
42
 
68
- ## Do not guess fields under ambiguity
43
+ ## Do Not Print Raw CSV
69
44
 
70
- If the field is uncertain:
45
+ Read CSV files with pandas. Summarize computed results, not raw rows.
71
46
 
72
- - do not bounce across tools
73
- - do not guess ids
74
- - do not switch from one read tool to another by trial and error
75
- - do not keep retrying different guessed field names in a loop
47
+ ## Do Not Rename Source Files
76
48
 
77
- Correct recovery:
49
+ CSV columns are directly readable and field-id anchored: `record_id`, `<字段标题>__field_<id>`. Use those columns directly in pandas.
78
50
 
79
- 1. `record_browse_schema_get`
80
- 2. if several plausible candidates remain, ask the user to confirm from a short list
81
- 3. build the DSL only after the field is clear
51
+ ## Do Not Trust Sparse Dimensions
82
52
 
83
- 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.
53
+ Before final grouping, run a field-quality profile. If the selected field is mostly blank, say so and downgrade the claim.
84
54
 
85
- Examples of the right recovery question:
55
+ Rules of thumb:
86
56
 
87
- - “我找到两个可能的字段:`线索来源`、`来源渠道`。你要按哪个字段统计?”
88
- - “目前最像‘来源’的字段有这三个:`来源`、`来源渠道`、`获客来源`。请确认你要按哪个字段分析。”
57
+ - Overall blank rate above 40%: not a primary conclusion dimension.
58
+ - Any compared period blank rate above 80%: do not use that field for period comparison.
59
+ - A sparse field can support only `已填写样本观察`.
89
60
 
90
- ## Do not try to control paging manually
61
+ If the user asks for a semantic field such as `板块`, test nearby candidates like product, platform, module, stage, source, owner, or department before concluding.
91
62
 
92
- `record_access` hides paging and follows the backend's native paging capability. `record_analyze` hides paging and scan budget on purpose.
63
+ ## Do Not Hide Incomplete Access
93
64
 
94
- - Do not invent `page_size`
95
- - Do not invent `requested_pages`
96
- - Do not invent `scan_max_pages`
97
- - Do not rename CSV columns before analysis; use `metadata_files.schema` / `metadata_files.readme` to interpret `field_<id>` columns.
98
- - Do not invent `auto_expand_pages`
99
- - Do not invent `max_rows`
65
+ If `needs_scope`, no CSV exists. Ask for a time/business scope.
100
66
 
101
- When the result is incomplete:
67
+ If `partial`, use only subset wording and avoid full-population claims.
102
68
 
103
- 1. narrow the scope with views or filters
104
- 2. reduce the analysis problem into smaller field_id-based access requests
105
- 3. keep the answer at `初步观察` or `部分结果` if completeness is still not enough
69
+ If field meaning is ambiguous, ask the user to confirm from a short list.
106
70
 
107
- ## Do not guess metric semantics from loose business wording
71
+ ## Do Not Guess Metrics
108
72
 
109
- Before building the DSL, first decide whether the question needs:
73
+ Before fetching data, decide whether the request needs count, sum, average, distinct count, ratio, ranking, trend, or comparison.
110
74
 
111
- - `count`
112
- - `sum`
113
- - `avg`
114
- - `distinct_count`
115
- - a ratio with numerator + denominator
116
- - a sorted ranking result
75
+ ## Do Not Call A Ratio Without Denominator
117
76
 
118
- Do not jump straight from words like `数量`, `人数`, `单量`, or `金额` to one assumed metric.
77
+ For penetration, conversion, or share:
119
78
 
120
- ## Do not hide partial completion
121
-
122
- If the user asked for several outputs and only part of them is stable:
123
-
124
- - say which parts are complete
125
- - say which parts are still unresolved
126
- - do not present the answer as fully finished
127
-
128
- ## Do not send unsupported formula or div-style metrics into `record_analyze`.
129
-
130
- Examples to avoid:
131
-
132
- - `{"op":"div", ...}`
133
- - metric items with `formula`, `expr`, `numerator`, or `denominator`
134
-
135
- Correct recovery:
136
-
137
- 1. query the source metrics with separate DSLs
138
- 2. confirm both sides are complete and compatible
139
- 3. compute the derived ratio outside MCP in the reasoning layer
79
+ 1. define numerator
80
+ 2. define denominator
81
+ 3. query compatible source data
82
+ 4. compute in Python
83
+ 5. report numerator and denominator
140
84
 
141
- ## Do not call something a ratio without the denominator
85
+ ## Normalize Relative Dates
142
86
 
143
- If the user asks for penetration / conversion / 占比:
87
+ Convert relative phrases into exact ranges before `record_access`.
144
88
 
145
- 1. define numerator
146
- 2. define denominator
147
- 3. query both sides explicitly
148
- 4. only then compute and report the ratio
89
+ - `今年5月` -> exact May 1 to May 31 in the current year
90
+ - `去年同期` -> same date range in previous year
91
+ - `最近30天` -> exact rolling start/end dates