Commit 67fe9d19 by luoqi

fix(摄入): 补义齿维护族 + 扩根/松牙固定/用氟/洁牙 —— 救回 11,672 条被整条丢弃的治疗

薛希明 TS0K018752 牙14;15;16;17;25;26;27:
  2025-01-19 戴活动义齿(10 颗,含本次全部信号牙位)
  2026-05-21 复诊,主诉「上颌假牙松2周」,检查所见「活动义齿修复,义齿卡环松」
             诊断「牙缺失 14;15;16;17;25;26;27」+ 本次治疗「卡环加力」(牙位完全一致)
2025-01 的戴牙被 2026-05 重记的诊断挡在时间门外;当天那条本可以过门的「卡环加力」
含词表一个词都不含 → 落 _default 整条丢弃 → 生产库里那天只有诊断没有治疗 → 误召。

── 影响面用真实引擎代码回放 DW 全量得出,不是手工估 ──
把 fact_emr_treatment_out 的 135,457 个 distinct treatName 全量喂给 runDerive(normalize)
+ resolveDictIncludes(真实字典) + classifyByKeyword(真实分类器),并按 manifest 的
route_by_pattern 先剔掉「建议/推荐」和复查词:
  改前  命中 2,146,498 / 分流 501,468 / **丢弃 218,881 EMR(35,817 词形)**
  改后  命中 2,158,170 / 分流 501,468 / **丢弃 207,209 EMR(34,493 词形)**
  → 救回 11,672 EMR / 1,324 词形,新丢 0 词形(无回归)

── 加了什么 ──
① prosthodontic += 卡环, 基托, 重衬, 假牙   478 EMR / 216 词形
   四个词临床上只属于活动义齿。基托选磨 49、卡环加力 40、重衬 26、紧卡环 21…
② endodontic    += 扩根                    604 EMR,与已收的「根备」同一动作
③ periodontic   += 松牙固定                269 EMR,牙周炎松动牙夹板固定
④ preventive    += 用氟                  4,470 EMR,与「涂氟」同一动作
   (preventive 不在结构 resolver 里 → 只补治疗史,不改召回判定)
⑤ periodontic   += 洁牙(独立规则,none: 清洁牙) 5,894 EMR
   裸「洁牙」当初被刻意拿掉是怕误命中散文「清洁牙面」。改成单开一条挂 none:
   「清洁牙面/清洁牙齿/清洁牙间隙」(332 EMR)照旧丢弃,其余全收。none 不挂原规则
   是为了混合句「清洁牙面,龈下刮治」仍由原规则正常命中。

── 碰撞全部实测,不是推理 ──
活动矫治器也有卡环/基托,但 orthodontic 排在 prosthodontic 之前 → 矫治器卡环调整 /
正畸基托调磨 / 保持器重衬 全部仍归 orthodontic;扫了 DW 里全部不含正畸词的卡环/基托
记录,无一条正畸语义。扩弓不含扩根。洁牙后树脂充填仍归 restorative。

只改 actual 侧(resolver 读的那份);planned 侧本就与 actual 有意分歧(它保留裸洁牙和
裸二期,因计划名无散文),沿用「加牙/活托」只加 actual 的先例。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
parent 3454c739
...@@ -17,7 +17,10 @@ keyword_mapping: ...@@ -17,7 +17,10 @@ keyword_mapping:
# ⚠️ "二期" 必须限定到「种植二期」:裸"二期"会误吞"二期隐形矫正"(正畸)等 → 误判 implant。 # ⚠️ "二期" 必须限定到「种植二期」:裸"二期"会误吞"二期隐形矫正"(正畸)等 → 误判 implant。
# 种植语境的二期都带"种植"(种植二期);ortho 的"二期隐形矫正/二期矫正"靠下面 orthodontic 兜住。 # 种植语境的二期都带"种植"(种植二期);ortho 的"二期隐形矫正/二期矫正"靠下面 orthodontic 兜住。
- { value: implant, any: [种植, 即拔即种, 植体, 种植二期] } - { value: implant, any: [种植, 即拔即种, 植体, 种植二期] }
- { value: endodontic, any: [根管, RCT, 牙髓, 开髓, 根备, 根充, 盖髓, 摘髓, 根尖] } # 扩根 = 根管扩大预备的口语写法,与已收的「根备」同一动作。DW 实测 604 EMR(扩根 474 /
# 扩根换药 39 / 扩根封药 19 …)全部落 _default 被丢 —— 患者根管做到一半在系统里等于没做过。
# 碰撞已验:「扩弓」是正畸但不含「扩根」;含扩根的 DW 全量无非牙髓语义。
- { value: endodontic, any: [根管, RCT, 牙髓, 开髓, 根备, 根充, 盖髓, 摘髓, 根尖, 扩根] }
- { value: orthodontic, any: [正畸, 矫治, 矫正, 托槽, 保持器, 粘附件, 隐适美, 隐形矫, 扩弓, 错颌, 错合] } - { value: orthodontic, any: [正畸, 矫治, 矫正, 托槽, 保持器, 粘附件, 隐适美, 隐形矫, 扩弓, 错颌, 错合] }
- { value: cosmetic, any: [贴面, 漂白, 美白] } - { value: cosmetic, any: [贴面, 漂白, 美白] }
# 修复/备牙/取模:收 C.10 治疗痕迹(修复后/修复术后/全瓷桥修复后/备牙后/重新取模后)。 # 修复/备牙/取模:收 C.10 治疗痕迹(修复后/修复术后/全瓷桥修复后/备牙后/重新取模后)。
...@@ -27,7 +30,15 @@ keyword_mapping: ...@@ -27,7 +30,15 @@ keyword_mapping:
# 裸「加牙」58 条(50 带牙位)全部落 _default 被丢,患者整次修复在系统里不存在 → 误召缺失牙。 # 裸「加牙」58 条(50 带牙位)全部落 _default 被丢,患者整次修复在系统里不存在 → 误召缺失牙。
# 变体「活动义齿加牙/义齿加牙/取模加牙」已被 义齿/取模 收,只有裸词和「活托X」漏。 # 变体「活动义齿加牙/义齿加牙/取模加牙」已被 义齿/取模 收,只有裸词和「活托X」漏。
# 碰撞已验:「根管治疗加牙周治疗」含"加牙"但被上方 ② endodontic 的「根管」先吃,安全。 # 碰撞已验:「根管治疗加牙周治疗」含"加牙"但被上方 ② endodontic 的「根管」先吃,安全。
- { value: prosthodontic, any: [, , 义齿, 修复体, 修复, 备牙, 取模, 桩核, 桩冠, 戴牙, 全瓷, 烤瓷, 重新粘接, 加牙, 活托] } # 卡环/基托/重衬/假牙(2026-08-28 薛希明 TS0K018752 牙14;15;16;17;25;26;27):活动义齿 2025-01
# 已戴,2026-05 复诊主诉「上颌假牙松2周」,当次治疗写「卡环加力」,牙位与缺牙诊断完全一致 ——
# 该词落 _default 整条被丢,那次就诊在系统里没有任何治疗 → 判「缺失牙未启动修复」误召。
# 这四个词临床上**只属于活动义齿**:卡环(卡子)/基托(托板)/重衬/假牙(口语)。
# DW 全量回放:478 EMR / 216 词形被丢(基托选磨 49、卡环加力 40、重衬 26、紧卡环 21…)。
# 碰撞已验:① 活动矫治器也有卡环/基托,但 orthodontic 规则排在本行**之前**,含
# 正畸/矫治/矫正/托槽/保持器的一律先被判走;② 扫了 DW 全部不含正畸词的卡环/基托记录,
# 无一条是正畸语义,全是义齿维护。
- { value: prosthodontic, any: [, , 义齿, 修复体, 修复, 备牙, 取模, 桩核, 桩冠, 戴牙, 全瓷, 烤瓷, 重新粘接, 加牙, 活托, 卡环, 基托, 重衬, 假牙] }
# ⭐ 明确充填动作(充填/去腐/备洞/嵌体/垫底/补牙)压过 preventive: # ⭐ 明确充填动作(充填/去腐/备洞/嵌体/垫底/补牙)压过 preventive:
# "去腐,备洞,...树脂充填,窝沟封闭"(dispose 散文)是补牙(restorative),不能因含"窝沟封闭" # "去腐,备洞,...树脂充填,窝沟封闭"(dispose 散文)是补牙(restorative),不能因含"窝沟封闭"
# 被误判 preventive → 非 resolver → 误召(马思煦@46)。注:"开髓去腐"等根管语境已被上方 endodontic 先收。 # 被误判 preventive → 非 resolver → 误召(马思煦@46)。注:"开髓去腐"等根管语境已被上方 endodontic 先收。
...@@ -40,8 +51,18 @@ keyword_mapping: ...@@ -40,8 +51,18 @@ keyword_mapping:
# SRP = scaling & root planing(龈下刮治+根面平整)的国际通用缩写,正是 perio_no_srp 子场景 # SRP = scaling & root planing(龈下刮治+根面平整)的国际通用缩写,正是 perio_no_srp 子场景
# 要认的那个治疗。DW 实测 SRP 648 + 局部SRP 40 + SRP+冲洗上药 76,此前全部落 _default 被丢 —— # 要认的那个治疗。DW 实测 SRP 648 + 局部SRP 40 + SRP+冲洗上药 76,此前全部落 _default 被丢 ——
# 患者做完牙周基础治疗仍被召「牙周炎未做基础治疗」。含 SRP 的 DW 全量已扫,无非牙周语义。 # 患者做完牙周基础治疗仍被召「牙周炎未做基础治疗」。含 SRP 的 DW 全量已扫,无非牙周语义。
- { value: periodontic, any: [洁治, 洗牙, 龈上, 龈下, 刮治, 牙周, 喷砂, 细洁, SRP] } # 松牙固定 = 牙周炎松动牙夹板固定,牙周治疗动作。DW 实测 269 EMR 被丢。
- { value: preventive, any: [涂氟, 防龋, OHI, 口腔卫生宣教] } - { value: periodontic, any: [洁治, 洗牙, 龈上, 龈下, 刮治, 牙周, 喷砂, 细洁, SRP, 松牙固定] }
# 裸「洁牙」单开一条并挂 none —— 上一行**不能**直接加它:actual 侧收的是 dispose 散文,
# 「清洁牙面 / 清洁牙齿 / 清洁牙间隙」都含「洁牙」二字(332 EMR),那是充填/正畸流程里的
# 清洁动作,不是洗牙。none 挂在独立规则上,原规则的语义不受影响(混合句「清洁牙面…龈下刮治」
# 仍由上一行正常命中;DW 全量实测这类 0 条,单开一条是为了将来也不会被误挡)。
# 收益:DW 全量回放 5,894 EMR(全口超声洁牙 1,359 / 超声洁牙 1,059 / 超声波洁牙 475 …)——
# 此前患者洗过牙仍被召「牙周炎未做基础治疗」。planned 侧本就收裸「洁牙」(计划名无散文)。
- { value: periodontic, any: [洁牙], none: [清洁牙] }
# 用氟:与已收的「涂氟」同一动作的另一种写法。DW 实测 4,470 EMR 被丢(局部用氟 4,436)。
# 注:preventive 不在结构家族 resolver 里,本词只补治疗史完整性,不改召回判定。
- { value: preventive, any: [涂氟, 用氟, 防龋, OHI, 口腔卫生宣教] }
# 缝线:「拆线」已在宿主精确表(拆线→surgical,37,253 条正常落库),但措辞变体 # 缝线:「拆线」已在宿主精确表(拆线→surgical,37,253 条正常落库),但措辞变体
# 「拆除缝线」699 条(665 带牙位)漏了 —— 同一临床动作。收「缝线」一并覆盖变体。 # 「拆除缝线」699 条(665 带牙位)漏了 —— 同一临床动作。收「缝线」一并覆盖变体。
# 碰撞已验:「拆除」不含「拔除/切除」,不会被本行前面的词误命中。 # 碰撞已验:「拆除」不含「拔除/切除」,不会被本行前面的词误命中。
......
...@@ -94,3 +94,86 @@ describe('既有裁决顺序不被新词打乱', () => { ...@@ -94,3 +94,86 @@ describe('既有裁决顺序不被新词打乱', () => {
expect(cat(s)).toBe(want); expect(cat(s)).toBe(want);
}); });
}); });
// ═══════════════════════════════════════════════════════════════
// 2026-08-28 补:义齿维护族 + 扩根 / 松牙固定 / 用氟 / 洁牙
// 缘起 薛希明 TS0K018752 —— 活动义齿早已戴上,复诊「卡环加力」落 _default 整条丢弃,
// 那次就诊在系统里没有任何治疗 → 判「缺失牙未启动修复」误召。
// 每个新词锁一条**碰撞**用例:新词最大的风险不是没命中,是抢了前面该赢的。
// ═══════════════════════════════════════════════════════════════
describe('义齿维护族 → prosthodontic(卡环/基托/重衬/假牙)', () => {
it.each([
'卡环加力', // 薛希明本例
'紧卡环',
'调整卡环',
'加卡环',
'基托选磨',
'舌侧基托选磨',
'基托缓冲',
'基托修理',
'重衬',
'下颌重衬',
'调假牙',
'戴活动假牙',
'调磨假牙',
])('%s', (s) => {
expect(cat(s)).toBe('prosthodontic');
});
it('⭐ 碰撞:活动矫治器也有卡环/基托 —— orthodontic 排在前面,必须先赢', () => {
expect(cat('矫治器卡环调整')).toBe('orthodontic');
expect(cat('正畸基托调磨')).toBe('orthodontic');
expect(cat('保持器重衬')).toBe('orthodontic');
});
it('⭐ 碰撞:种植/根管语境仍归各自类目(prosthodontic 排在它们之后)', () => {
expect(cat('种植覆盖义齿卡环加力')).toBe('implant');
expect(cat('根管治疗后基托修理')).toBe('endodontic');
});
});
describe('扩根 → endodontic', () => {
it.each(['扩根', '扩根换药', '扩根封药', '继续扩根', '定长扩根'])('%s', (s) => {
expect(cat(s)).toBe('endodontic');
});
it('⭐ 碰撞:正畸「扩弓」不含「扩根」,不被误吃', () => {
expect(cat('扩弓')).toBe('orthodontic');
});
});
describe('松牙固定 → periodontic', () => {
it.each(['松牙固定', '松牙固定术', '下前牙松牙固定'])('%s', (s) => {
expect(cat(s)).toBe('periodontic');
});
});
describe('用氟 → preventive', () => {
it.each(['局部用氟', '定期局部用氟'])('%s', (s) => {
expect(cat(s)).toBe('preventive');
});
});
describe('洁牙 → periodontic(独立规则 + none: 清洁牙)', () => {
it.each(['洁牙', '全口超声洁牙', '超声洁牙', '超声波洁牙', '洁牙检查'])('%s', (s) => {
expect(cat(s)).toBe('periodontic');
});
it('🔴 「清洁牙面 / 清洁牙齿」含「洁牙」二字但不是洗牙 —— 必须仍然丢弃', () => {
// actual 侧收的是 dispose 散文,这三串在生产共 332 条,是充填/正畸流程里的清洁动作
expect(cat('清洁牙面')).toBeUndefined();
expect(cat('清洁牙齿')).toBeUndefined();
expect(cat('清洁牙间隙')).toBeUndefined();
expect(cat('清洁牙齿 交付新牙套')).toBeUndefined();
});
it('🔴 none 挂在独立规则上,不能误挡混合句 —— 上一行的牙周词仍须命中', () => {
expect(cat('清洁牙面,龈下刮治')).toBe('periodontic');
expect(cat('清洁牙面后行龈上洁治')).toBe('periodontic');
});
it('⭐ 碰撞:含充填动作的仍归 restorative(restorative 排在 periodontic 之前)', () => {
expect(cat('洁牙后树脂充填')).toBe('restorative');
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment