# 变更审计记录：coach_service 绩效档位硬编码修复

| 字段 | 值 |
|------|-----|
| 日期 | 2026-03-19 16:45:10 |
| Prompt-ID | P20260319-163903 |
| Session-ID | 4782a6d3 |
| Session 路径 | docs/audit/session_logs/2026-03/19/43_4782a6d3_162502 |

## 操作摘要

RNS1 全系列 SPEC 审计发现 `coach_service.py` 中 `DEFAULT_TIER_NODES` 硬编码 `[0, 100, 130, 160, 190, 220]` 违反 feiqiu-data-rules 规则 6（绩效档位禁止硬编码）。配置表 `cfg_performance_tier` 实际有效值为 `[0, 120, 150, 180, 210]`，两者完全不一致。本次修复删除硬编码常量，改为从配置表动态读取，并修复 `perf_target` 推算逻辑。

## 本次对话文件变更

### 新增文件
- `docs/audit/prompt_logs/prompt_log_20260319_163903.md`
- `docs/audit/session_logs/2026-03/19/43_4782a6d3_162502/main_01_bab93fd1.md`

### 删除文件
- `docs/audit/session_logs/2026-03/19/43_4782a6d3_162502/main_01_48b374db.md`

## 风险评估

- **风险等级**：低
- `_FALLBACK_TIER_NODES` 作为降级保底，配置表查询失败不会导致崩溃
- `perf_target` 推算逻辑简单：找到第一个大于当前工时的 tier 节点
- 影响范围仅限 `coach_service.get_coach_detail()` 接口返回的 `tierNodes` 和 `perf_target` 字段

## 合规检查

| 检查项 | 状态 |
|--------|------|
| 新增迁移 SQL | 无 |
| DDL 基线更新 | 不适用 |
| OpenAPI spec 同步 | 不适用（`api_changed: false`） |
| BD 手册更新 | 不适用（无 DB schema 变更，仅读取已有配置表） |
| 文档同步 | `code_without_docs` 为空，无缺失 |

## 改动注解

### `apps/backend/app/services/coach_service.py`
- 变更类型：修改
- 原始原因：`DEFAULT_TIER_NODES` 硬编码 `[0, 100, 130, 160, 190, 220]` 违反 feiqiu-data-rules 规则 6，且与配置表实际值 `[0, 120, 150, 180, 210]` 完全不一致，导致前端展示的绩效档位与实际业务规则脱节
- 思路分析：
  1. 删除 `DEFAULT_TIER_NODES` 硬编码常量，替换为 `_FALLBACK_TIER_NODES`（值更新为与配置表一致的 `[0, 120, 150, 180, 210]`），仅在配置表查询失败时作为降级使用
  2. `_build_tier_nodes()` 签名从 `(salary_data: dict)` 改为 `(conn, site_id)`，内部调用 `fdw_queries.get_performance_tiers()` 从 `app.v_cfg_performance_tier` 视图读取当前有效档位
  3. `get_coach_detail()` 中 `perf_target` 从 `salary_this.get("next_tier_hours", 0.0)`（总是返回 0）改为根据 `tier_nodes` 和当前工时动态推算下一档目标
- 修改结果：绩效档位数据源从硬编码切换为配置表驱动，符合 feiqiu-data-rules 规则 6；`perf_target` 能正确反映下一档目标工时；降级机制确保配置表不可用时不崩溃

### `apps/backend/app/services/fdw_queries.py`
- 变更类型：修改
- 原始原因：配合 `coach_service.py` 的档位读取改造，需要更新 `get_salary_calc()` 中关于 `tier_nodes` 的注释说明
- 思路分析：`get_salary_calc()` 返回的 `tier_nodes` 字段改为空数组，注释明确说明"由 `coach_service._build_tier_nodes()` 从 `cfg_performance_tier` 读取"，职责分离清晰
- 修改结果：`fdw_queries` 不再承担档位数据的传递职责，`get_performance_tiers()` 函数（上一个 session 已创建）作为独立查询入口供 `coach_service` 调用
