# 移除 `customfield_10159` 和 `customfield_10160` 后的 TCOC/GTOC Assign 逻辑

> 注意：本文是旧的 JiraPort Assign 重构设计。新的 Assign 所有权切换以
> [JiraPort L1/L2/L3 Assign 所有权切换方案](assign-ownership-cutover.md) 为准；
> 新方案启用后，本文不再适用于 TCOC。

## 文档状态与范围

本文定义从 Assign 链路中完全移除 `customfield_10159` 和
`customfield_10160` 后，TCOC/GTOC 工单的目标分配行为。

当前代码仍然读取这两个字段。实现本文设计时需要同步修改：

- `pkg/resolver/handler/action/assign.go`
- `pkg/entity/issue.go`
- `config/prod-tidbcloud/assign-oncall.yml`
- `config/prod-tidbcloud/assign.yml`

修改完成后，TCOC/GTOC Assign 不再依赖：

- `customfield_10159`（`kind`）；
- `customfield_10160.labels.assign`；
- `customfield_10160.labels.oncall_team`；
- `customfield_10160` 中的其他 label，包括 `tier`、`provider_type`、
  `o11y_biz_type`、`stability_governance`、`visibility`、`owner_id` 和
  `job`。

因此：

- Internal 工单不再跳过 Assign；
- `assign: none` 不再阻止 Assign；
- `assign: user@pingcap.com` 不再覆盖 Assignee；
- `oncall_team` label 不再覆盖 Component 路由；
- 依赖 10160 正向匹配的规则被删除，不会通过直接删掉匹配条件而扩大范围；
- 原来使用 10160 负向条件表达“默认归属”的规则，由本文的确定性 Component
  映射取代。

## Assign 入口

### L2/SEE Assign

TCOC/GTOC 工单的 Priority 从 `Undefined` 发生变化时，策略路由会创建
`l2-assign` 或 `l2-assign-direct-l3` Notification。

L2 Assign 不受本次字段移除影响：

1. 读取工单的第一个 Component，通过 `l2-assign.yml` 解析为
   `support_compute`、`support_storage` 或 `support_tools`。
2. 从 Oncall 服务查询该 Team 当前的 Primary Oncall。
3. 如果返回多人，通过分配历史选择一人。
4. 将选中的工程师写入 `customfield_10053`（L2 Assignee）。

`l2-assign` 在失败后每两小时重试，达到配置的重试次数后转入 L3 Assign。
`l2-assign-direct-l3` 在第一次 L2 Assign 失败后立即转入 L3 Assign。

### L3 Jira Assignee Assign

以下情况会触发 L3 Assign：

- TCOC/GTOC 工单状态变为 `ESCALATE TO L3`；
- L2 Assign 策略进入 L3 fallback。

状态变为 `ESCALATE TO L3` 时，`oncall-assign` 等待五秒后执行公共
`assign` 命令。

目标流程为：

```text
TCOC/GTOC assign event
  -> 应用不依赖 10159/10160 的特殊规则
  -> 通过 Project + 第一个 Component 解析 Oncall Team
     （TCOC 可优先使用 customfield_10164 的 Oncall Tier）
  -> 查询 Team 当前的 Primary Oncall
  -> 使用分配历史选择一个候选人
  -> 更新 Jira Assignee
  -> 更新 Jiraport 中保存的 Assignee，并触发 InnerUpdatedAssigneeEvent
```

与当前 Matcher extractor 一致，只使用 Jira 的第一个 Component。

### Component 规则范围

本文只保留下列 Component 的路由规则：

```text
Account, Alert, Ansible, Audit, BR, Billing, Clinic, Cloud DM,
Cloud Import, Cloud Service, Cluster Service, DBaaS Frontend, DDL, DM,
Dashboard, Dataservice, Dumpling, GitOps, Import/export, Jira, Loader,
Monitoring, OpenAPI, PD, PM, Performance Tuning, PiTR, Prometheus, Quota,
Resource Control, Serverless, TEM, Test-only, TiCDC, TiDB, TiDB Binlog,
TiDB Cloud, TiDB Compute, TiDB Lightning, TiDB OOM, TiDB Operator,
TiDB Optimizer, TiDB Transaction, TiDB charsets, TiDB connection,
TiDB partitions, TiDB-Operator, TiDBCloud CICD, TiEM, TiFlash, TiKV,
TiKV BR, TiKV CDC, TiProxy, TiSpark, TiUP, Tools, central,
cluster management, gardener, import/export, ops, other,
sync-diff-inspector
```

其他 Component 不再由本文定义映射。上述 Component 中没有出现在后续
映射表里的条目，表示当前没有可保留的确定性 Oncall Team 映射，
本文不为它们新增隐式归属。

## 匹配优先级

规则按以下顺序执行。除非规则配置 `continue: true` 用于收集多个人员，否则第一个
匹配结果生效：

1. 不依赖 10159/10160 的特殊规则；
2. TCOC Oncall Tier 覆盖规则；
3. Project 专属 Component 映射；
4. TCOC/GTOC 公共 Component 映射；
5. 旧 `assign.yml` fallback；
6. 两套 Matcher 都无法产生候选人时进入 Assign 错误处理。

### 保留的特殊规则

下列现有规则不依赖 `customfield_10159` 或 `customfield_10160`，继续优先于
Component 映射：

| 匹配条件                                                                      | Assign 目标         |
| ----------------------------------------------------------------------------- | ------------------- |
| Summary 以 `TiDBClusterLogBackupLagHigh` 结尾                                 | `br`                |
| Summary 是 `assign-oncall.yml` 中现有的 `BizChangefeed...`/CDC delay 规则之一 | `resilience`        |
| Summary 为 `TiDBP999LatencySurgeNextGen`，且处于配置的夜间时段                | 配置中的指定工程师  |
| Summary 以 `For2mForWeTechTest` 结尾                                          | 配置中的指定工程师  |
| Cluster ID 属于配置的 WeTech POC Cluster                                      | `dedicated_service` |
| Summary 为 `PDLeaderChange` 或 `PDTSOFailed`                                  | `pd`                |

同时依赖 10160 label 的规则不再保留。例如，要求
`provider_type=aws-free-tier` 或要求特定 `stability_governance` 的规则不会退化为
仅按 Summary 或 Component 匹配。

### TCOC Oncall Tier 覆盖规则

TCOC 继续使用 Jira Oncall Tier 字段 `customfield_10164`，因为它不在本次移除
范围中。

对于以下 Cloud Service Component：

```text
TiDB Cloud, Cloud Service, Cluster Service, GitOps, cluster management, Tools
```

优先映射为：

| Project | Oncall Tier  | Oncall Team  |
| ------- | ------------ | ------------ |
| TCOC    | `Serverless` | `serverless` |
| TCOC    | `TiDB X`     | `premium`    |

Oncall Tier 为空或为其他值时，继续执行普通 Component 映射。GTOC 没有
Oncall Tier 覆盖规则。

## Project 专属 Component 映射

Project 专属规则优先于后面的公共规则。

### TCOC

| Components（精确名称或正则 alternatives）                                                                                                                      | Oncall Team         |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
| `TiKV CDC`, `TiCDC`, `TiDB Lightning`, `TiDB Binlog`, `sync-diff-inspector`, `Cloud DM`, `import/export`, `Cloud Import`, `Dumpling`, `Quota`, `BR`, `TiKV BR` | `tidb_x_tools`      |
| `TiDB Cloud`, `Cloud Service`, `Cluster Service`, `GitOps`, `cluster management`, `Tools`                                                                      | `dedicated_service` |

TCOC Oncall Tier 覆盖规则在本表之前执行。因此，Cloud Service Component 的
Oncall Tier 为 `Serverless` 或 `TiDB X` 时，分别 Assign 给 `serverless` 或
`premium`，而不是 `dedicated_service`。

### GTOC

| Components（精确名称或正则 alternatives）                                                          | Oncall Team       |
| -------------------------------------------------------------------------------------------------- | ----------------- |
| `Tools`, `TiDB Lightning`, `TiDB Binlog`, `sync-diff-inspector`, `DM`, `import/export`, `Dumpling` | `ingress_service` |
| `TiKV CDC`, `TiCDC`                                                                                | `ticdc`           |
| `BR`, `TiKV BR`                                                                                    | `br`              |

## TCOC/GTOC 公共 Component 映射

Project 专属规则未命中时，使用以下公共映射：

| Components（精确名称或正则 alternatives）                                                                                                        | Oncall Team      |
| ------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------- |
| `Serverless`                                                                                                                                     | `serverless`     |
| `Clinic`                                                                                                                                         | `clinic`         |
| `Alert`                                                                                                                                          | `resilience`     |
| `OpenAPI`, `Dashboard`, `Dataservice`                                                                                                            | `global_control` |
| `Monitoring`, `Prometheus`                                                                                                                       | `o11y`           |
| `Billing`                                                                                                                                        | `billing`        |
| `Account`                                                                                                                                        | `account`        |
| `TiProxy`                                                                                                                                        | `tiproxy`        |
| `TiSpark`                                                                                                                                        | `serverless`     |
| `DBaaS Frontend`                                                                                                                                 | `frontend`       |
| `PD`                                                                                                                                             | `pd`             |
| `DDL`, `TiDB`, `TiDB connection`, `TiDB partitions`, `TiDB charsets`, `TiUP`, `Performance Tuning`, `TiDB Optimizer`, `TiDB OOM`, `TiDB Compute` | `tidb_common`    |
| `TiDB Transaction`                                                                                                                               | `tidb_txn`       |
| `TiDB-Operator`, `TiDB Operator`                                                                                                                 | `operator`       |
| `TiFlash`                                                                                                                                        | `tiflash`        |
| `TiKV`, `PiTR`                                                                                                                                   | `tikv_unified`   |

Component 匹配保持大小写敏感，本文不引入隐式大小写转换。

仅通过 10160 label 区分 NextGen、free-tier、dev-tier、governance 或
dedicated-global-service 的规则被移除。未出现在上述表格中的
Component 不再由本文定义映射。

## 从 Team 选择并 Assign 工程师

解析出 Oncall Team 后：

1. 请求 `GET /api/v1/teams/{team}/current-oncall`。
2. 只使用 `current_engineer_emails`，Backup Engineer 不参与候选。
3. 通过 Engineer 服务/数据库解析每个邮箱。
4. 有多个候选人时调用 `SelectAssigneeFromCandidate`：
   - 所有人都有历史记录时，选择最久没有被 Assign 的人；
   - 存在无历史记录的人时，从无历史记录的人中随机选择；
   - 分配历史查询失败时，使用第一个候选人。
5. 通过邮箱查询 Atlassian Account，并调用 Jira `UpdateAssignee`。
6. 更新 Jiraport 中保存的 Assignee，并触发 `InnerUpdatedAssigneeEvent`。

## Fallback 与错误处理

以下情况会从 Oncall Matcher 回退到 `assign.yml`：

- 无法解析 Oncall Team；
- Oncall 服务没有返回 Primary Engineer；
- Engineer 邮箱无法解析；
- Jira Assign 失败。

旧 Matcher 也必须删除全部 10159/10160 extractor 和对应路由。剩余的
Project/Component 规则返回 Category ID 或直接邮箱，然后继续使用分配历史选人。

如果 Oncall Matcher 和旧 Matcher 都没有产生候选人：

- `assign` action 返回错误；
- `oncall-assign` policy 通过 `ErrorAssignEvent` 执行配置的静态兜底通知；
- 工单不会被自动 Assign。

不设置默认 Oncall Team，避免缺失 Component ownership 时被静默隐藏。

## 对非 Assign 逻辑的影响

`Issue.OncallTeam`、Manager escalation 和 `leader` receiver 当前也读取
`customfield_10160.labels.oncall_team`。移除字段后，它们必须复用本文定义的
Project/Component Team Resolver。否则 Jira Assignee 可以正常分配，但后续升级到
Team Manager 时会返回 `no oncall_team to escalate`。

## 代码与配置位置

- TCOC/GTOC 策略路由：`config/prod-tidbcloud/policy-route.yml`
- Assign 状态机：`config/prod-tidbcloud/policy.yml`
- Primary Oncall Matcher：`config/prod-tidbcloud/assign-oncall.yml`
- 旧 Category Matcher：`config/prod-tidbcloud/assign.yml`
- 公共 Assign command：`pkg/resolver/handler/action/assign.go`
- L2 Assign：`pkg/resolver/handler/action/custom.go`
- 分配历史选人：`pkg/db/assign.go`
- Oncall API client：`pkg/clients/oncall/oncall.go`
