# 审计记录：skip_words 误过滤 remark 业务字段修复

- 日期：2026-02-14（Asia/Shanghai）
- Prompt-ID：P20260214-190000
- 原始 Prompt：

> goods_stock_movements 的 remark 字段在 md 文档中。检查下为什么对比出错了？

## 直接原因

`extract_response_fields` 函数的 `skip_words` 集合包含 `'remark'` 和 `'note'`，本意是过滤 Markdown 表头行中的列标题词（如 `| 备注 | remark |`），但 `remark` 在 `goods_stock_movements`、`member_balance_changes`、`store_goods_master` 等表的 MD 文档中是真实的 API 响应业务字段名，被误过滤导致比对结果出现假差异（"ODS有/MD无"）。

修复方案：从 `skip_words` 移除 `'remark'` 和 `'note'`。表头行过滤已被中文词（`'字段'`/`'类型'`/`'说明'`/`'备注'`）和英文词（`'field'`/`'type'`/`'description'`）充分覆盖。

## Files Changed

- `scripts/compare_ods_vs_summary_v2.py` — 从 `skip_words` 移除 `'remark'`/`'note'`，添加 CHANGE 标记注释，更新 AI_CHANGELOG
- `docs/reports/ods_vs_summary_comparison_v2.json` — 重新生成（完全匹配从 12→14）

## 比对结果变化

| 指标 | 修复前 | 修复后 |
|------|--------|--------|
| 完全匹配 | 12 | 14 |
| 有差异 | 11 | 9 |
| 无 ODS 表 | 2 | 2 |

新增完全匹配：`goods_stock_movements`（19/19）、`member_balance_changes`（28/28）
`store_goods_master` 的 `remark` 也被正确提取（ODS有/MD无 从 1→0，但仍有 2 个 MD有/ODS无）

## Risk / Verify

- 风险：修改了比对脚本的过滤逻辑，可能导致某些 MD 文档中表头行的 "remark" 列标题被误识别为字段。但检查所有 25 个 MD 文档，表头行均使用中文"字段"而非英文"remark"，因此无此风险。
- 回滚：将 `'remark'` 和 `'note'` 加回 `skip_words` 即可
- 验证：`python scripts/compare_ods_vs_summary_v2.py`，确认完全匹配 14 张、有差异 9 张
- 无 DB schema 变更，无需更新 bd_manual
- 无 ETL 运行时影响（纯分析脚本）

---

## 追加：P20260214-200000 — skip_words 替换为分隔行检测

- 日期：2026-02-14（Asia/Shanghai）
- Prompt-ID：P20260214-200000
- 原始 Prompt：

> group_buy_packages 的 type 字段在 md 文档中。检查下为什么对比出错了？

### 直接原因

`skip_words` 硬编码 `'type'` 来过滤表头词，但 `group_buy_packages` 的 API 响应中 `type` 是真实业务字段名。这是 `skip_words` 方案的根本缺陷——无法区分表头词和同名业务字段。

修复方案：彻底移除 `skip_words`，改用 Markdown 表格结构检测（分隔行 `|------|` 的前一行即为表头行）来跳过表头，从根本上消除同名冲突。

### Files Changed

- `scripts/compare_ods_vs_summary_v2.py` — 用 `separator_pattern` + `header_lines` 替代 `skip_words`，添加 CHANGE 标记注释，更新 AI_CHANGELOG
- `docs/reports/ods_vs_summary_comparison_v2.json` — 重新生成

### 比对结果变化

- `group_buy_packages`：ODS有/MD无 不再包含 `type`（匹配 38→39）
- 总体：完全匹配 14、有差异 9、无ODS表 2（不变，因 `type` 匹配后 `tableAreaNameList` 仍为 MD有/ODS无）

### Risk / Verify

- 风险：移除 `skip_words` 后，如果某个 MD 文档的表头行第一列恰好是合法的 camelCase/snake_case 标识符（如 `| field | type | description |`），且该行前面没有分隔行，则可能被误提取。但所有 25 个 MD 文档均使用中文表头（`| 字段 | 类型 | 说明 |`），且分隔行格式标准，无此风险。
- 回滚：恢复 `skip_words` 字典和原有的 `for line in response_text.split('\n')` 循环即可
- 验证：`python scripts/compare_ods_vs_summary_v2.py`
- 无 DB schema 变更，无需更新 bd_manual
- 无 ETL 运行时影响（纯分析脚本）

---

## 追加：P20260214-210000 — siteProfile 误跳过 + goodsCategoryList 包装器忽略

- 日期：2026-02-14（Asia/Shanghai）
- Prompt-ID：P20260214-210000
- 原始 Prompt：

> siteprofile肯定在md文件中存在。检查下，怎么写的对比代码？stock_goods_category_tree的goodsCategoryList是数据的上级节点，ODS中进行穿透了，MD中忽略这个字段。

### 直接原因

两个独立问题：

1. siteProfile 子节跳过逻辑（`in_site_profile`）会跳过整个子节包括 `siteProfile` 字段本身。但在 `table_fee_transactions`、`platform_coupon_redemption_records` 等表中，`siteProfile` 是 object/jsonb 字段应被提取，只需跳过其展开的子字段。
2. `goodsCategoryList` 是 `stock_goods_category_tree` 的上级数组容器节点，ODS 穿透存储子元素而非容器本身，MD 中应忽略此字段。

### Files Changed

- `scripts/compare_ods_vs_summary_v2.py` — 重写 siteProfile 子节跳过逻辑（保留字段本身，只跳过展开子字段）；新增 `WRAPPER_FIELDS` 忽略列表；添加 CHANGE 标记注释；更新 AI_CHANGELOG
- `docs/reports/ods_vs_summary_comparison_v2.json` — 重新生成（完全匹配从 14→17）

### 比对结果变化

| 指标 | 修复前 | 修复后 |
|------|--------|--------|
| 完全匹配 | 14 | 17 |
| 有差异 | 9 | 6 |
| 无 ODS 表 | 2 | 2 |

新增完全匹配：`platform_coupon_redemption_records`（26/26）、`table_fee_transactions`（42/42）、`stock_goods_category_tree`（11/11）
`table_fee_discount_records` 的 siteProfile 也被正确匹配（ODS有/MD无 从 9→8）

### Risk / Verify

- 风险：siteProfile 子节跳过逻辑变更后，如果某个 MD 文档在 siteProfile 子节中展开了子字段且第一行不是 siteProfile 本身，可能导致子字段被误提取。但检查所有相关 MD 文档，siteProfile 子节的第一个表格字段均为 siteProfile 本身，无此风险。
- 回滚：恢复原有的 `in_site_profile` 简单跳过逻辑，移除 `WRAPPER_FIELDS` 即可
- 验证：`python scripts/compare_ods_vs_summary_v2.py`
- 无 DB schema 变更，无需更新 bd_manual
- 无 ETL 运行时影响（纯分析脚本）
