---
name: requirements-analysis
description: 当用户提出统计、取数、报表、指标、转化率、漏斗、留存、活跃、GMV、同环比、SQL/Hive/Spark/PySpark 数据开发需求时使用。先把模糊业务问题澄清成可交付的数据需求规格说明书 DRD，不直接写 SQL，不调用 MCP，不提交作业。
---

# Requirements Analysis（需求澄清）

## 目标

把一句可能含糊的数据需求整理成正式 DRD。重点不是快点写 SQL，而是先把统计对象、时间窗口、指标分子分母、维度、表字段、join 和输出要求固定下来，避免“SQL 看起来对但数字口径错”。

本 skill 的输出是 `requirements_output`，下游只能基于它推进，不得重新解释业务口径。

## 工作顺序

1. 复述业务目标：这个统计用于评估什么，最终交付什么。
2. 定义输出粒度：结果一行代表什么维度组合。
3. 明确统计对象：用户、订单、交易、设备、账户等。
4. 明确时间口径：自然日、T-1 完整日、滚动窗口、时区、事件时间字段。
5. 明确指标口径：分子、分母、去重键、过滤条件、空值策略。
6. 明确维度口径：渠道、城市、产品、日期等分组字段来自哪张表。
7. 明确数据来源：候选表、候选字段、字段含义、状态枚举、金额单位。
8. 明确关联关系：主表、维表、join key、join 类型、1:N 风险。
9. 明确结果要求：输出列、排序、是否落表、是否允许 overwrite。
10. 如果任一关键口径不明确，停止并提问；如果已明确，输出 DRD 和 `requirements_output`。

## 必问歧义

- “近 30 天”是自然日、T-1 完整日，还是滚动到当前时刻。
- “新用户”是首次注册、首次登录、首次下单、首次激活还是首次付费。
- “成功”对应哪些状态码，退款、撤销、部分成功是否计入。
- “转化率”的分子、分母、事件顺序、去重键和转化窗口是什么。
- 分组维度来自事实表还是维表；维表缺失时是否保留 NULL。
- 多表 join 后是否会产生重复行，是否要先去重或聚合。
- 输出是临时查询还是要写入目标表。

## 时间口径硬规则

对“近 N 天按 T-1 完整日”，统一解释为左闭右开窗口：

```text
[start, end) = [current_date() - N days, current_date())
```

Spark/Hive SQL 应表达为：

```sql
event_time >= date_sub(current_date(), N)
AND event_time < current_date()
```

不要使用下面写法表示 timestamp 完整日窗口：

```sql
event_time BETWEEN date_add(current_date(), -N) AND date_add(current_date(), -1)
```

因为它很容易只覆盖到结束日期的 00:00:00，漏掉 T-1 白天的数据。

## 转化口径硬规则

转化类需求必须写清：

- 分母人群，例如“窗口内首次登录的新用户”。
- 分子人群，例如“该新用户注册后存在成功付费”。
- 事件顺序，例如 `pay_time >= register_time`。
- 后置事件是否也需要在统计窗口内。
- 去重键，例如 `user_id`。

如果用户说“注册后付费”，必须把“后”写进 DRD，不允许只写“注册且付费”。

## 正式 DRD 输出

当关键口径已明确时，必须先输出可读 DRD，再输出 YAML 摘要。

```markdown
## 需求说明

### 业务目标
...

### 统计口径
- 统计对象：...
- 时间范围：近 N 天 T-1 完整日，`event_time >= date_sub(current_date(), N)` 且 `event_time < current_date()`
- 维度：...
- 指标：...

### 涉及表
| 表名 | 用途 | 粒度 | 使用字段 |
|---|---|---|---|

### 表关系
| 左表字段 | 右表字段 | Join 类型 | 风险 |
|---|---|---|---|

### 字段清单
| 表名 | 字段 | 用途 | 角色 |
|---|---|---|---|

### 实现逻辑
1. ...

### 待确认问题
无，或列出阻塞问题。
```

## 结构化输出

```yaml
requirements_output:
  status: READY_FOR_METADATA | NEED_USER_CONFIRMATION
  business_goal: "一句话业务目标"
  grain: "结果一行代表什么"
  time_window:
    description: "时间窗口"
    timezone: "时区"
    event_time_hint: "候选时间字段"
    lower_bound_sql: "date_sub(current_date(), N)"
    upper_bound_sql: "current_date()"
    boundary: "left_closed_right_open"
  metrics:
    - name: "指标名"
      formula: "业务公式"
      numerator: "分子"
      denominator: "分母"
      dedupe_key: "去重键"
      order_constraint: "例如 pay_time >= register_time"
      null_policy: "空值处理"
  dimensions:
    - "分组维度"
  filters:
    - "过滤条件"
  candidate_tables:
    - business_role: "事实表/维表/码表/结果表"
      table_hint: "候选物理表"
  candidate_fields:
    - business_name: "业务字段名"
      role: dimension | metric | filter | time | join_key | output
      table_hint: "候选表"
      column_hint: "候选字段"
      required: true
  join_hints:
    - left: "表A.字段"
      right: "表B.字段"
      type_hint: left | inner | right | full | unknown
      cardinality_hint: "1:1 | 1:N | N:1 | N:N | unknown"
  output_columns:
    - "输出列"
  write_intent:
    mode: query_only | insert_into | insert_overwrite | unknown
    target_table: "可为空"
    overwrite_confirmed: false
  pending_questions: []
```

## 停止条件

只要 `pending_questions` 非空，就输出 `NEED_USER_CONFIRMATION`，不要进入元数据校验，更不要写 SQL。
