update, translate skill.md

This commit is contained in:
tao.chen
2026-06-22 10:08:52 +08:00
parent 71a23d639c
commit f9b03384ab
6 changed files with 565 additions and 541 deletions
+91 -82
View File
@@ -1,99 +1,107 @@
---
name: sql-context-builder
description: Use when assembling the single trusted SQL context that the SQL generator and reviewer will consume. Triggers include "build SQL context", "固化 join key", "table aliases", "列出来自哪张表", "准备写 SQL", "context 已经齐了". Consumes a validated Logic Plan + Field Mapping and produces a normalized SQL Context with stable aliases, frozen join keys, and explicit fact/dimension tagging. The SQL generator MUST NOT re-derive any of this.
description: 当需要组装 SQL 生成器与评审器共同消费的、唯一可信的 SQL Context 时使用。触发词包括"build SQL context""固化 join key""table aliases""列出来自哪张表""准备写 SQL""context 已经齐了"。消费已校验的 Logic Plan Field Mapping,产出带有稳定 alias、固化 join key、显式 fact/dimension 标记的标准化 SQL Context。SQL 生成器**不得**再重新推导其中任何一项。
---
# SQL Context Builder
# SQL Context Builder(SQL 上下文构建器)
## Overview
## 概述(Overview)
Freeze every decision that the SQL generator would otherwise re-invent. Aliases, join keys, field sources, types, role tags (fact vs dimension vs filter), and time columns are all pinned here exactly once. The output is the **single trusted input** for `sql-review` and for any SQL-emitting step.
把 SQL 生成器本来要重复发明的所有决策一次性固化下来:alias、join key、字段来源、类型、角色标签(fact / dimension / filter)、时间列,都在这里只此一次地钉死。输出是 `sql-review` 及任何 SQL 输出步骤的**唯一可信输入**。
Core principle: **anything not in the SQL Context does not exist for downstream skills.** If a downstream skill needs something new, the request must go back through `metadata-validator` and `logic-planner` first.
核心原则:**任何不在 SQL Context 中的字段,下游 skill 视同不存在。** 如果下游 skill 还需要新内容,请求必须先回退到 `metadata-validator` `logic-planner`
## When to Use
## 何时使用(When to Use)
Use when:
- `logic-planner` returned status `PLANNED`
- The user is about to write Spark SQL and you need a normalized context (aliases, join keys, column sources)
- Multiple SQL drafts need to be generated against the *same* logic — context guarantees they stay consistent
**使用场景:**
Do NOT use when:
- `logic-plan.status` is `NEED_USER_CONFIRMATION` — go back to `logic-planner`
- The SQL is trivial (one table, no join) — you can still build the context, but skip if the user explicitly opts out
- The task is to translate the plan into SQL — that is a separate concern from this skill
- `logic-planner` 返回状态 `PLANNED`
- 用户即将写 Spark SQL,需要一份规范化的 context(alias、join key、字段来源)
- 同一份逻辑要产出多版 SQL 草稿 — context 保证它们保持一致
## Inputs
**不要使用场景:**
1. `logic_plan` from `logic-planner` (status `PLANNED`)
2. `field_mapping` from `metadata-validator` (status `VALIDATED`)
3. Original `validation_result` for table-level metadata (types, sources)
- `logic-plan.status``NEED_USER_CONFIRMATION` — 回到 `logic-planner`
- SQL 极简单(单表无 join) — 仍然建议构建 context,除非用户明确跳过
- 任务是把 plan 翻译成 SQL — 那是另一回事,不是本 skill 的职责
## Workflow
## 输入(Inputs)
1. 来自 `logic-planner``logic_plan`(状态 `PLANNED`)
2. 来自 `metadata-validator``field_mapping`(状态 `VALIDATED`)
3. 原始 `validation_result`(用于表级元数据:类型、来源)
## 工作流(Workflow)
```dot
digraph sql_context_builder {
"Read logic_plan + field_mapping + validation_result" [shape=box];
"Assign stable alias to every table" [shape=box];
"Freeze join keys (left_alias.field = right_alias.field)" [shape=box];
"Resolve every field to (alias, column, type, source_file)" [shape=box];
"Tag each field: dimension | metric | filter | time | join_key" [shape=box];
"Mark fact vs dimension tables" [shape=box];
"Verify Logic Plan fields all exist in context" [shape=box];
"All required fields present?" [shape=diamond];
"Emit SQL Context" [shape=box];
"Emit SQL Context + missing_fields" [shape=box];
"读取 logic_plan + field_mapping + validation_result" [shape=box];
"为每张表分配稳定 alias" [shape=box];
"固化 join key(left_alias.field = right_alias.field)" [shape=box];
"把每个字段解析为 (alias, column, type, source_file)" [shape=box];
"为每个字段打标签:dimension | metric | filter | time | join_key" [shape=box];
"标记事实表 / 维度表" [shape=box];
"校验 Logic Plan 的字段在 context 中全部存在" [shape=box];
"所有必需字段都齐全?" [shape=diamond];
"输出 SQL Context" [shape=box];
"输出 SQL Context + missing_fields" [shape=box];
"Read logic_plan + field_mapping + validation_result" -> "Assign stable alias to every table";
"Assign stable alias to every table" -> "Freeze join keys (left_alias.field = right_alias.field)";
"Freeze join keys (left_alias.field = right_alias.field)" -> "Resolve every field to (alias, column, type, source_file)";
"Resolve every field to (alias, column, type, source_file)" -> "Tag each field: dimension | metric | filter | time | join_key";
"Tag each field: dimension | metric | filter | time | join_key" -> "Mark fact vs dimension tables";
"Mark fact vs dimension tables" -> "Verify Logic Plan fields all exist in context";
"Verify Logic Plan fields all exist in context" -> "All required fields present?";
"All required fields present?" -> "Emit SQL Context" [label="yes"];
"All required fields present?" -> "Emit SQL Context + missing_fields" [label="no"];
"读取 logic_plan + field_mapping + validation_result" -> "为每张表分配稳定 alias";
"为每张表分配稳定 alias" -> "固化 join key(left_alias.field = right_alias.field)";
"固化 join key(left_alias.field = right_alias.field)" -> "把每个字段解析为 (alias, column, type, source_file)";
"把每个字段解析为 (alias, column, type, source_file)" -> "为每个字段打标签:dimension | metric | filter | time | join_key";
"为每个字段打标签:dimension | metric | filter | time | join_key" -> "标记事实表 / 维度表";
"标记事实表 / 维度表" -> "校验 Logic Plan 的字段在 context 中全部存在";
"校验 Logic Plan 的字段在 context 中全部存在" -> "所有必需字段都齐全?";
"所有必需字段都齐全?" -> "输出 SQL Context" [label="yes"];
"所有必需字段都齐全?" -> "输出 SQL Context + missing_fields" [label="no"];
}
```
## Rules
## 规则(Rules)
### Alias Assignment
- One alias per table, never reused.
- Fact table (the one with the primary metric) gets a short alias first (`o`, `f`, `t1`).
- Dimension tables get meaningful aliases (`c` for customer, `p` for product, `ch` for channel).
- Aliases are **frozen** here. The SQL generator and reviewer must not invent new ones.
### Alias 分配
### Join Key Freezing
- For every `logic_plan.steps[kind=join]`, freeze the exact predicate:
- 一张表一个 alias,绝不重用
- 事实表(承载主指标的表)优先拿到短 alias(`o``f``t1`)
- 维度表用有意义的 alias(`c` 代表 customer,`p` 代表 product,`ch` 代表 channel)
- alias **在此处固化**,SQL 生成器与评审器不得再发明新 alias
### Join Key 固化
- 对每条 `logic_plan.steps[kind=join]`,固化精确的谓词:
- `left_alias.col1 = right_alias.col2`
- Include join type (inner / left / right / full / semi / anti).
- Include cardinality assumption carried over from the Logic Plan.
- If two tables could join on multiple keys, freeze the chosen one here. Other candidates are out of scope for SQL.
- 包含 join 类型(inner / left / right / full / semi / anti)
- 沿用 Logic Plan 中的 cardinality 假设
- 如果两张表有多种可能的 join key,在此处固化为所选的那一个,其他候选不再纳入 SQL 范畴
### Field Resolution
For every field used in the Logic Plan, record:
- `alias` (which table it lives on)
- `column` (physical name)
- `type` (from `validation_result`)
- `source_file` (which metadata file it came from — for traceability)
- `role`: one of `dimension` | `metric` | `filter` | `time` | `join_key` | `derived`
### 字段解析(Field Resolution)
A field may have multiple roles (e.g. a `customer_id` that is both `join_key` and `dimension`); list all.
对 Logic Plan 用到的每个字段,记录:
### Fact vs Dimension Tagging
- The table containing the primary event/measure is `fact`.
- Tables that enrich (customer, product, channel, city) are `dimension`.
- One fact per query. If the Logic Plan implies multiple facts, raise a `pending_question` — that is a planning issue, not a context issue.
- `alias`(字段所在表)
- `column`(物理列名)
- `type`(取自 `validation_result`)
- `source_file`(元数据文件来源 — 用于追溯)
- `role`:取自 `dimension` | `metric` | `filter` | `time` | `join_key` | `derived` 之一
### Coverage Check
- Every step in `logic_plan.steps` must reference fields that exist in this context.
- Every `field_mapping` entry must appear in this context.
- Every `group_by` and `order_by` field must be tagged.
- Every metric in `aggregate` must have a `metric` tag.
- Every predicate in `filter` must reference a `filter` or `time` tag.
一个字段可以有多个 role(例如 `customer_id` 同时是 `join_key``dimension`),全部列出。
## Output Contract
### Fact vs Dimension 标记
- 承载主要事件/度量的表为 `fact`
- 起丰富作用的表(customer、product、channel、city)为 `dimension`
- 一条 query 只能有一个 fact。如果 Logic Plan 隐含多张事实表,作为 `pending_question` 抛出 — 那是规划问题,不是 context 问题
### 覆盖度校验
- `logic_plan.steps` 中的每一步引用的字段都必须存在于本 context
- 每条 `field_mapping` 都必须出现在本 context
- 每个 `group_by``order_by` 字段都必须有标签
- `aggregate` 中的每个指标都必须有 `metric` 标签
- `filter` 中的每条谓词都必须引用 `filter``time` 标签的字段
## 输出契约(Output Contract)
```yaml
sql_context:
@@ -149,21 +157,22 @@ sql_context:
status: <READY | NEED_USER_CONFIRMATION>
```
## Forbidden Behaviors
## 禁止行为(Forbidden Behaviors)
| Rationalization | Reality |
| 自我说服 | 现实 |
|---|---|
| "I'll let the SQL generator pick aliases" | Aliases are frozen here. Re-aliasing downstream breaks `sql-review`. |
| "The join key is obvious, skip the freeze" | The whole point of this skill is to freeze join keys. |
| "Field type doesn't matter, it's all strings in SQL" | Type drives aggregations, casts, and partition-pruning decisions. |
| "Derived columns can be invented in SQL" | Every derived column must already appear in the Logic Plan. |
| "Multiple facts? Just join them all" | Multi-fact queries are a Logic Plan issue. Surface and stop. |
| "alias 让 SQL 生成器自己选" | alias 就在此处固化。下游重新起 alias 会破坏 `sql-review` |
| "join key 太显然,跳过固化" | 整个 skill 的意义就在于此 — 把 join key 钉死。 |
| "字段类型无所谓,SQL 里都是字符串" | 类型决定了聚合、cast、分区裁剪的策略。 |
| "派生列到 SQL 阶段再发明就行" | 每个派生列都必须在 Logic Plan 里就出现。 |
| "多张事实表?全 join 上就行" | 多事实是 Logic Plan 的问题,要暴露并停止。 |
## Completion Criteria
## 完成判定(Completion Criteria)
`status: READY` only when:
- Every Logic Plan step has matching entries in this context
- `missing_fields` is empty
- Every metric has a defined `agg` and `expr`
- Every join has a frozen key and a type
- The time grain is set
仅当**以下全部**成立时,`status: READY`:
- Logic Plan 的每一步在本 context 中都有对应条目
- `missing_fields` 为空
- 每个指标都有 `agg``expr`
- 每个 join 都有固化的 key 和 type
- 时间粒度已设定