fix: 第16轮搜索审计修复 — all_not/group_negated分离 + _parse_primary重复组 + 错误显示
CI / backend (push) Canceled after 0s
CI / frontend (push) Canceled after 0s

- Bug 2 (MEDIUM): all_not 混淆外部NOT与内部NOT,新增 group_negated
  字段区分,_pubmed_conditions 改用 pp.group_negated[idx] 替代 all_not
- Bug 1 (MEDIUM): _parse_primary 括号组内重复group赋值,只处理
  group_id < 0 的未分配terms,_parse_or_expr 增加 depth>0 守卫
- Bug 3 (MEDIUM): SearchView.vue 搜索错误显示为"no results",
  新增 searchError ref + NResult 错误面板
- Bug 4 (LOW): literature.py UUID类型转换优化
This commit is contained in:
34047007@qq.com
2026-07-28 14:08:46 +08:00
parent 1f46f05586
commit de1f4a4bb8
6 changed files with 85 additions and 13 deletions
+46
View File
@@ -1207,6 +1207,52 @@
---
## 第十六轮:第 16 轮审计修复(4 项修复 + 3 项记录)
**日期**2026-07-29
**提交**`(待推送)`
**数量**:4 项修复 + 3 项记录
**触发**:用户第 11 次要求全面检查(Round 163 并行 agentNormal 搜索边缘、前端参数、NOT 检测)
**测试**1007 全部通过 + 前端 build 通过
### Bug-1 (MEDIUM): `_parse_primary` 括号组内重复 group 赋值
- **文件**`pubmed_query_parser.py:706-709`
- **根因**`_parse_or_expr` 在 `A OR B AND C` 时为 `[B, C]` 创建 sub-group。随后 `_parse_primary` 将所有 terms(含已 sub-group 的)再统一加到 parent group。sub-group 内的 term 同时出现在两个 group → `_pubmed_conditions` 遍历 group 列表时为其生成两套条件 → SQL 中产生重复/多余的过滤条件,静默排除合法结果
- **影响**`NOT (A OR B AND C)` 类带 sub-group 的括号组查询可能返回零结果
- **修复**`_parse_primary` 只从 `t.group_id < 0`(未分配)的 term 创建 parent group。sub-group 已分配的不再加入。同时增加 depth 守卫:`_parse_or_expr` 在 `self._depth > 0`(括号内)时直接 flat 返回,不创建 sub-group
### Bug-2 (MEDIUM): `all_not` 混淆外部 NOT 与内部 NOT
- **文件**`search_engine.py:1134-1172`
- **根因**`all_not = all(t.is_not for t in group)` 无法区分 `NOT (A OR B)`(外部 NOT:应生成 `not_(or_(A, B))` 和 `(NOT A OR NOT B)`(内部 NOT:应生成 `or_(not_(A), not_(B))`)。两者都 `all_not=True`,但语义完全不同
- **修复**
- 解析器端:新增 `ParsedPubmedQuery.group_negated: list[bool]` 字段,`_parse_primary` 在创建 parent group 时记录是否为外部 NOT wrapper
- 引擎端:用 `group_negated[idx]` 替代 `all_not`,外部 NOT 走 `not_(combine_fn(g_neg))`,内部 NOT 走 `combine_fn(g_pos + g_neg_with_not_)`
- **验证**`NOT (A OR B)` 与 `(NOT A OR NOT B)` 生成不同的 SQL 条件组合
### Bug-3 (MEDIUM): 搜索错误显示为"no results"
- **文件**`SearchView.vue:365-367`
- **根因**catch 块只调用 `toast.apiError()`(瞬态通知提示),但 `results = []` 导致 `<NEmpty>` 显示"未找到匹配文献",用户以为搜索有结果只是条件过严,实际是后端错误
- **修复**:新增 `searchError` ref,catch 时设置明确错误信息,模板条件渲染 `<NResult>` 错误面板替代 `NEmpty`。成功搜索时清除 `searchError`
### Bug-4 (LOW): UUID 类型转换在中文标签子查询中
- **文件**`literature.py:293-294`
- **根因**`[str(t) for t in _tag_matches]` 将 UUID 转字符串后传给 `in_(...)`,某些驱动下可能导致类型不匹配
- **修复**:改为 `list(_tag_matches)` 传递原生 UUID 对象
### 审计结果汇总
| 审计维度 | 结果 |
|---------|------|
| Normal 搜索边缘情况 | ✅ `_parse_primary` 重复 group 已修复。PubMed 降级路径 field tag 清洗已正确。ATM 展开括号剥离已正确 |
| 前端参数发送 | ✅ SearchView.vue 完整发送全部 28 个参数,`SearchRequestBody` 类型正确 |
| NOT 检测 | ✅ `group_negated` 新增 track`all_not` 已替换。NOT-wrapped parens 与 sub-group 交互部分缓解(depth guard)。剩余 De Morgan 双重否定场景(LOW,理论正确性,实际罕见) |
---
截至 2026-07-29,剩余 7 项已知限制:
| ID | 问题 | 原因 | 影响 |