@qingflow-tech/qingflow-app-user-mcp 1.0.4 → 1.0.5

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 (27) hide show
  1. package/README.md +2 -2
  2. package/package.json +1 -1
  3. package/pyproject.toml +2 -1
  4. package/skills/qingflow-app-user/SKILL.md +2 -1
  5. package/skills/qingflow-app-user/references/data-gotchas.md +5 -2
  6. package/skills/qingflow-app-user/references/public-surface-sync.md +5 -3
  7. package/skills/qingflow-app-user/references/record-patterns.md +9 -0
  8. package/skills/qingflow-record-analysis/SKILL.md +103 -166
  9. package/skills/qingflow-record-analysis/agents/openai.yaml +2 -2
  10. package/skills/qingflow-record-analysis/references/analysis-gotchas.md +56 -110
  11. package/skills/qingflow-record-analysis/references/analysis-patterns.md +106 -119
  12. package/skills/qingflow-record-analysis/references/business-context.md +74 -0
  13. package/skills/qingflow-record-analysis/references/confidence-reporting.md +49 -72
  14. package/skills/qingflow-record-analysis/references/data-access-playbook.md +106 -0
  15. package/skills/qingflow-record-analysis/references/pandas-recipes.md +172 -0
  16. package/skills/qingflow-record-analysis/references/report-format.md +76 -0
  17. package/skills/qingflow-record-insert/SKILL.md +2 -2
  18. package/skills/qingflow-record-update/SKILL.md +1 -1
  19. package/src/qingflow_mcp/backend_client.py +55 -1
  20. package/src/qingflow_mcp/cli/commands/record.py +44 -5
  21. package/src/qingflow_mcp/cli/formatters.py +101 -1
  22. package/src/qingflow_mcp/public_surface.py +2 -1
  23. package/src/qingflow_mcp/response_trim.py +173 -9
  24. package/src/qingflow_mcp/server.py +15 -9
  25. package/src/qingflow_mcp/server_app_user.py +26 -10
  26. package/src/qingflow_mcp/tools/record_tools.py +12860 -8811
  27. package/skills/qingflow-record-analysis/references/dsl-templates.md +0 -93
package/README.md CHANGED
@@ -3,13 +3,13 @@
3
3
  Install:
4
4
 
5
5
  ```bash
6
- npm install @qingflow-tech/qingflow-app-user-mcp@1.0.4
6
+ npm install @qingflow-tech/qingflow-app-user-mcp@1.0.5
7
7
  ```
8
8
 
9
9
  Run:
10
10
 
11
11
  ```bash
12
- npx -y -p @qingflow-tech/qingflow-app-user-mcp@1.0.4 qingflow-app-user-mcp
12
+ npx -y -p @qingflow-tech/qingflow-app-user-mcp@1.0.5 qingflow-app-user-mcp
13
13
  ```
14
14
 
15
15
  Environment:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qingflow-tech/qingflow-app-user-mcp",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Operational end-user MCP for Qingflow records, tasks, comments, and directory workflows.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qingflow-mcp"
7
- version = "1.0.4"
7
+ version = "1.0.5"
8
8
  description = "User-authenticated MCP server for Qingflow"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -29,6 +29,7 @@ dependencies = [
29
29
  "openpyxl>=3.1,<4.0",
30
30
  "pydantic>=2.8,<3.0",
31
31
  "pycryptodome>=3.20,<4.0",
32
+ "pypdf>=5.0,<6.0",
32
33
  "python-socketio[client]>=5.11,<6.0",
33
34
  ]
34
35
 
@@ -54,7 +54,7 @@ Route to exactly one of these specialized paths:
54
54
  - If the task involves member, department, or relation fields and the user only has natural names/titles, keep the same route; direct write now supports backend-native auto resolution and may return `needs_confirmation` with candidates instead of failing blind
55
55
  - If the task involves linked visibility, upstream/downstream field dependencies, reference-driven auto fill, or formula-driven defaulting, keep the same insert/update route and read field-level `linkage` from the schema before composing payloads
56
56
  - If the task is about subtable writes, still route to the matching insert/update skill, but shape the payload as parent subtable field -> row array; do not route users toward top-level leaf selectors
57
- - If the task is insert-focused and readback consistency matters, keep the same route and prefer `record_get / record_list` with `output_profile="normalized"` after the write
57
+ - If the task is insert-focused and readback/detail context matters, keep the same route and prefer the single-record detail readback after the write; use normalized list readback only when batch row shape is needed
58
58
  - If the user sounds like an ordinary workflow assignee rather than a system operator, prefer `$qingflow-task-ops` over direct record mutation whenever both paths could fit
59
59
  - If the task is about task discovery by natural language query, still route to `$qingflow-task-ops`; `task_list --query` now uses backend search first and only falls back to local matching when backend returns zero rows
60
60
  - If the task is about grouped distributions, ratios, rankings, trends, insights, or any final statistical conclusion, switch to `$qingflow-record-analysis`
@@ -68,6 +68,7 @@ Route to exactly one of these specialized paths:
68
68
  - if the task can stay read-only, do not write or act
69
69
  - if the task involves a user-uploaded import file, do not modify the file unless the user explicitly authorizes repair or normalization
70
70
  - if the task involves record import, call `app_get` first and inspect `data.import_capability` before template download, file repair, or import start
71
+ - if a record detail includes images or attachments, prefer the single-record detail tool's local paths: images from `media_assets.items[].local_path`, documents/tables from `file_assets.items[].local_path` and `extraction.text_path`; remote Qingflow file URLs are not stable direct-read targets
71
72
  - if the current MCP capability is unsupported, the workflow is awkward, or the user's need still cannot be satisfied after reasonable use, summarize the gap, ask whether to submit feedback, and call `feedback_submit` only after explicit user confirmation
72
73
 
73
74
  ## Shared Helper
@@ -4,10 +4,12 @@ For final statistics, grouped distributions, rankings, trends, or insight-style
4
4
 
5
5
  ## Record Reads
6
6
 
7
- - `record_list` is for browsing, export, and sample inspection only
8
- - `record_get` is for one exact record
7
+ - For analysis-style reads, use `record_access` through [$qingflow-record-analysis](../../qingflow-record-analysis/SKILL.md)
8
+ - `record_list` is for browsing and sample inspection only
9
+ - `record_get` is for one exact record and downloads readable detail-page images into `media_assets.items[].local_path` plus attachments/documents/tables into `file_assets.items[].local_path`
9
10
  - Use `record_browse_schema_get` when field titles are uncertain instead of guessing ids
10
11
  - Do not present paged browse output as if it were a grouped or full-population conclusion
12
+ - Use `record_export_direct` only when the user explicitly asks for export/download/Excel output
11
13
 
12
14
  ## Direct Writes
13
15
 
@@ -27,3 +29,4 @@ For final statistics, grouped distributions, rankings, trends, or insight-style
27
29
 
28
30
  - Subtable payloads stay under the parent table field as a row array
29
31
  - Attachment fields are two-step: upload first, then write the returned upload payload
32
+ - For reads, attachment/rich-text images returned by `record_get` should be opened from local `media_assets` paths, and non-image files should be read from `file_assets` local paths or `extraction.text_path`, instead of remote file URLs
@@ -8,11 +8,13 @@ It is not a user-facing product spec. It exists to prevent skill drift.
8
8
  ### User data
9
9
 
10
10
  - Read range first with `app_get`, then `record_browse_schema_get(view_id=...)`
11
+ - Treat `record_browse_schema_get.fields` as the selected Qingflow table view header schema; `record_access.fields` and `record_list` field selectors must stay aligned with it.
11
12
  - Standard flows:
12
- - browse / export detail: `app_get -> record_browse_schema_get -> record_list / record_get`
13
+ - analyze: `app_get -> record_browse_schema_get -> record_access -> Python`
14
+ - browse detail: `app_get -> record_browse_schema_get -> record_list / record_get`
15
+ - explicit export/download/Excel: `view_get -> record_export_*` or `record_export_direct`
13
16
  - insert: `record_insert_schema_get -> record_insert`
14
17
  - update: `record_update_schema_get -> record_update`
15
- - analyze: `app_get -> record_browse_schema_get -> record_analyze`
16
18
 
17
19
  ### Tasks
18
20
 
@@ -55,7 +57,7 @@ It is not a user-facing product spec. It exists to prevent skill drift.
55
57
  - Package public tools: do not regress to `package_create` / `package_attach_app` as the public default story
56
58
  - App editability: do not let `can_edit_form` imply app base-info writes
57
59
  - Portal and chart visibility: keep the public story on `portal_apply` / `app_charts_apply`, not low-level internal writes
58
- - Analysis fallback: standard path stays `record_analyze`, but complex tables may require explicit fallback modes
60
+ - Analysis path: standard path stays `record_access -> Python`
59
61
 
60
62
  ## Release Checklist For Skill Maintenance
61
63
 
@@ -10,6 +10,14 @@ Use `record_browse_schema_get -> record_list` when:
10
10
  - the target `record_id` is unknown
11
11
  - a delete target still needs confirmation
12
12
  - the user needs sample rows or a small export
13
+ - the user gives fuzzy text such as a company, project, bug, or contract name
14
+
15
+ For fuzzy lookup, pass `query` and optional `query_fields`. `record_list` returns at most 10 `data.items`, plus `data.pagination.total_count` and `lookup.next_action`.
16
+
17
+ - `lookup.next_action="record_get"`: read the single returned item with `record_get`
18
+ - `lookup.next_action="ask_user"`: ask the user to choose from returned `data.items`
19
+ - `lookup.next_action="refine_query"`: ask for a narrower keyword or add `query_fields`
20
+ - `lookup.next_action="broaden_query"`: remove overly narrow fields or ask for another clue
13
21
 
14
22
  ## Detail Pattern
15
23
 
@@ -18,6 +26,7 @@ Use `record_browse_schema_get -> record_get` when:
18
26
  - the exact `record_id` is known
19
27
  - the user needs one record in detail
20
28
  - a write target needs verification before action
29
+ - the user needs images or attachments shown on the detail page; read downloaded images from `media_assets.items[].local_path`, and read documents/tables from `file_assets.items[].local_path` or `extraction.text_path`
21
30
 
22
31
  ## Insert Pattern
23
32
 
@@ -1,200 +1,137 @@
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 DSL execution
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=...)`. 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.
10
+ Use this skill only for final statistical conclusions: counts, distributions, ratios, averages, rankings, trends, comparisons, and analysis reports.
15
11
 
16
- ## Step 1: `app_get` → Step 2: `record_browse_schema_get(view_id=...)` → Step 3: build DSL → Step 4: `record_analyze`
12
+ Default path, every time:
17
13
 
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 or an explicit fallback. Task/comment work stays in [$qingflow-task-ops](../qingflow-task-ops/SKILL.md).
21
-
22
- ## Execution Modes
23
-
24
- Choose the lightest mode that can still support a trustworthy conclusion:
25
-
26
- 1. `server_aggregate`
27
- - Default and preferred path
28
- - Use `record_analyze` directly after `app_get -> record_browse_schema_get`
29
-
30
- 2. `client_aggregate_from_record_list`
31
- - Allowed fallback when `record_analyze` is unstable, unsupported on the target view, or the table is complex enough that service-side aggregation is not trustworthy
32
- - Still requires `app_get -> record_browse_schema_get` first
33
- - Use only after disclosing that the result is a fallback built from detail rows
34
-
35
- 3. `cross_app_manual_reconcile`
36
- - 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
37
- - Be explicit that the conclusion is based on manual reconciliation rules, not one single DSL execution
38
-
39
- ## Fallback Ladder
40
-
41
- Trigger a fallback when any of these are true:
42
-
43
- - `record_analyze` is unstable or cannot complete the scan reliably
44
- - the target view is unsupported for analysis
45
- - field semantics are ambiguous enough that a server aggregate would be misleading
46
- - the question requires cross-app reconciliation
47
- - the question depends on organization-tree scope, historical department aliases, or other business rules that are not first-class MCP filters
48
-
49
- When you fall back:
50
-
51
- 1. Keep the standard read order: `app_get -> record_browse_schema_get`
52
- 2. State which fallback mode you chose
53
- 3. State whether the result is still full-scope or only a verified subset
54
- 4. State the time field, organization scope, and any alias mapping used
55
- 5. Prefer concrete numbers plus a conservative conclusion over broad wording
56
-
57
- ---
58
-
59
- ## DSL Contract
60
-
61
- ### DSL FORMAT (CRITICAL — read this FIRST)
14
+ ```text
15
+ app_get -> record_browse_schema_get(view_id=...) -> record_access -> Python/pandas -> final answer
16
+ ```
62
17
 
63
- ### Correct vs Wrong learn from these before building ANY DSL
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:
64
19
 
65
- **dimension item:**
66
- ```
67
- CORRECT: { "field_id": 9500572, "alias": "报价类型" }
68
- WRONG: 9500572 ← bare integer, not a dict
69
- ❌ WRONG: "报价类型" ← string, not a dict
70
- ❌ WRONG: { "field_id": 9500572, "title": "报价类型" } ← "title" is forbidden
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
71
24
  ```
72
25
 
73
- **metric item the key is `op`, NOT `type`/`agg`/`aggregation`:**
74
- ```
75
- CORRECT: { "op": "count", "alias": "记录数" }
76
- ✅ CORRECT: { "op": "sum", "field_id": 7, "alias": "总金额" }
77
- WRONG: { "type": "count" } ← "type" is NOT a valid key
78
- WRONG: { "agg": "count" } ← "agg" is NOT a valid key
79
- WRONG: { "aggregation": "count" } ← "aggregation" is NOT a valid key
80
- ```
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:
81
69
 
82
- **filter item — the key is `op`, NOT `operator`:**
83
- ```
84
- ✅ CORRECT: { "field_id": 2, "op": "between", "value": ["2024-03-01", "2024-03-31"] }
85
- ✅ CORRECT: { "field_id": 5, "op": "eq", "value": "已完成" }
86
- WRONG: { "field_id": 2, "operator": "between", "value": [...] } ← "operator" is forbidden
87
- WRONG: { "field_id": 2, "op": ">=", "value": "2024-03-01" } ← ">=" is not valid, use "gte"
70
+ ```json
71
+ {
72
+ "app_key": "APP_KEY",
73
+ "view_id": "system:all",
74
+ "columns": [{ "field_id": 2 }, { "field_id": 18 }],
75
+ "where": [{ "field_id": 2, "op": "between", "value": ["2026-05-01", "2026-05-31"] }],
76
+ "order_by": [{ "field_id": 2, "direction": "asc" }]
77
+ }
88
78
  ```
89
79
 
90
- **sort item:**
91
- ```
92
- ✅ CORRECT: { "by": "记录数", "order": "desc" } ← "by" references an alias
93
- ❌ WRONG: { "by": 9500572, "order": "desc" } ← field_id not allowed in sort
94
- ```
80
+ Never pass `page`, `page_size`, `limit`, `max_rows`, `timeout`, or `profile` to `record_access`.
95
81
 
96
- ### Allowed keys per item (ANY other key = error)
82
+ CSV columns are already readable and field-id anchored, for example `项目状态__field_343283094`. Do not expect separate `schema.json` or `README.md` files.
97
83
 
98
- | Item | Allowed keys only |
99
- |------|-------------------|
100
- | dimension | `field_id`, `alias`, `bucket` |
101
- | metric | `op`, `field_id`, `alias` |
102
- | filter | `field_id`, `op`, `value` |
103
- | sort | `by`, `order` |
84
+ For CLI use, write JSON argument files instead of embedding large JSON in shell text:
104
85
 
105
- ### `op` values
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
94
+ ```
106
95
 
107
- - metrics: `count`, `sum`, `avg`, `min`, `max`, `distinct_count`
108
- - filters: `eq`, `neq`, `in`, `not_in`, `gt`, `gte`, `lt`, `lte`, `between`, `contains`, `is_null`, `not_null`
109
- - For `count` metric: do NOT pass `field_id`. For all others: `field_id` is required.
110
- - If `metrics` is omitted or `[]`, defaults to `[{"op":"count","alias":"记录数"}]`.
96
+ ## Status Handling
111
97
 
112
- ---
98
+ Read `record_access.status` before reading files or writing conclusions.
113
99
 
114
- See [references/dsl-templates.md](references/dsl-templates.md) for complete copy-paste templates.
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.
115
104
 
116
- **Typical summary / distribution:**
117
- ```json
118
- {
119
- "dimensions": [{ "field_id": FIELD_ID_FROM_SCHEMA, "alias": "维度名" }],
120
- "metrics": [{ "op": "count", "alias": "记录数" }],
121
- "sort": [{ "by": "记录数", "order": "desc" }],
122
- "limit": 50,
123
- "strict_full": true
124
- }
125
- ```
105
+ ## Business Context
126
106
 
127
- **Typical time-filter / trend:**
128
- ```json
129
- {
130
- "dimensions": [{ "field_id": TIME_FIELD_ID, "alias": "月份", "bucket": "month" }],
131
- "metrics": [{ "op": "count", "alias": "记录数" }],
132
- "filters": [{ "field_id": TIME_FIELD_ID, "op": "between", "value": ["2024-03-01", "2024-03-31"] }],
133
- "sort": [{ "by": "月份", "order": "asc" }],
134
- "limit": 24,
135
- "strict_full": true
136
- }
137
- ```
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.
138
108
 
139
- Top-level arguments:
109
+ Example: if `烈焰组` and `飓风组` are sub-departments of `北斗部门`, apply that mapping in Python and state it in the answer.
140
110
 
141
- - `app_key`: required.
142
- - `dimensions`: `[]` = whole-table summary; `[{...}]` = grouped.
143
- - `strict_full`: `true` for final conclusions. `false` allows partial results.
144
- - `limit`: limits returned rows only, not scan scope.
145
- - `view_id`: the canonical browse selector. Prefer choosing it from `app_get.accessible_views`.
146
- - 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`.
147
- - 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.
148
- - `bucket` in dimensions: only for `suggested_time_fields`. Values: `day`/`week`/`month`/`quarter`/`year`/`null`.
111
+ ## Output Shape
149
112
 
150
- ---
113
+ Default to:
151
114
 
152
- ## RULES
153
-
154
- - 渗透率 / 转化率 / 占比类结论必须先定义分子和分母。
155
- - Do not claim a metric you did not query.
156
- - Derived ratios must be computed outside the DSL.
157
- - Before choosing a DSL shape, first decide whether the question needs `count`, `sum`, `avg`, `distinct_count`, `ratio`, or `ranking`.
158
- - Rankings must come from structured sorted results.
159
- - For partial answers, explicitly disclose which parts are complete and which parts remain unresolved.
160
- - Complex answers should default to `先结构、后解读`.
161
- - `between`: pass a two-item array.
162
- - Sort entries must reference an alias already defined in `dimensions` or `metrics`.
163
- - Final wording should stay as close as possible to schema titles.
164
- - Do not pass field titles, aliases, or guessed ids.
165
- - If `completeness.statement_scope=returned_groups_only` or `completeness.rows_truncated=true`, downgrade wording to returned groups only.
166
- - One DSL per question. Multiple small DSLs > one overloaded request.
167
- - `record_list` is not the default basis for final statistics. Use it only in an explicit fallback mode and disclose that fallback in the final answer.
168
- - Set `alias` for any metric you will sort by, compare, or quote.
115
+ 1. `结论`
116
+ 2. `关键数据`
117
+ 3. `口径与范围`
118
+ 4. `可信度 / 限制`
169
119
 
170
- ---
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.
171
122
 
172
- ## OUTPUT
173
-
174
- - Final answer must show concrete numbers.
175
- - Final answer must state which execution mode was used whenever the answer is not a straightforward `server_aggregate`
176
- - If `result.rows` exists, list each returned row; if there are more than 20 rows, show Top 20 and say so.
177
- - 占比 = 行指标值 / `result.totals.metric_totals` 总值;如 `metric_totals` 缺失,用各行之和作分母。
178
- - Prefer the structured `ranking` block when it exists.
179
- - `safe_for_final_conclusion=true` → `全量可信结论`
180
- - Otherwise → `初步观察`
181
- - `rows_truncated=true` → 用 `前 N 个分组`, 不用 `全部`/`所有`
182
- - If you used a fallback mode, explicitly disclose:
183
- - whether this is full-scope or a manually curated subset
184
- - which time field was used
185
- - which organization scope was used
186
- - whether any historical department aliases or cross-app joins were applied
123
+ ## References
187
124
 
188
- ## Feedback Escalation
125
+ Load only what is needed:
189
126
 
190
- - 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.
191
- - Ask whether the user wants you to submit product feedback.
192
- - Only after explicit user confirmation, call `feedback_submit`.
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)
193
134
 
194
- ## Resources
135
+ ## Feedback Escalation
195
136
 
196
- - Shared public-surface baseline: [public-surface-sync.md](../qingflow-app-user/references/public-surface-sync.md)
197
- - DSL templates: [references/dsl-templates.md](references/dsl-templates.md)
198
- - Analysis patterns: [references/analysis-patterns.md](references/analysis-patterns.md)
199
- - Confidence reporting: [references/confidence-reporting.md](references/confidence-reporting.md)
200
- - 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 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."
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."