Commit 362f484e by luoqi

fix(召回): 病历文本举证按场景开闸 —— 只开缺失牙,别的场景没验过就不开

上一版漏了作用域:抛光那条规则用 cfgFlags.polishImpliesRestoration 只对 K08 开,
本分支却没设闸,凡是 resolverCats 含 prosthodontic 的场景(整个结构家族
K00/K01/K02/K03/K04/K08/K09)都会触发。而我那 59 条人工复核**全是 missing_tooth**,
非缺牙场景一条没验过。

想补验,但非缺牙理由量太大(hard_tissue_damage 单独就 18 万条),导出复核的查询
两次 860s 超时 —— 也就是"验不完"。少召不报错,验不完就不该默认开。

改为 GAP_FLAGS_BY_PRIMARY.K08.treatedEvidenceFromEmrText,机制保持场景无关
(判据是牙位级的),开关按场景给。要给别的场景开,先把该场景的命中全量导出人工过一遍。

顺带记下通用性自查的其余结论(都通过):
 · 关联键 emr_external_id  source_encounter_external_id 都是 PAC 规范字段,非 host 字段名
 · 词表在 packages/types 共享层,收的是临床通用词(戴牙/假牙/义齿/修复体/烤瓷冠),
   无 host 痕迹 —— 符合「通用→共享,怪癖→宿主」的分层
 · 宿主不填主诉(如 FRIDAY)→ join 落空,分支自动失效,不报错
 · 类目闸对 K05/K07 天然为空(resolverCats 不含 prosthodontic),全口路径本就不接本表

测试补一例锁住开闸范围。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
parent 50a9c9a5
......@@ -39,6 +39,7 @@ export interface GapCfgFlags {
excludeCongenitalName?: boolean; // §E name 含"先天" → 正畸统筹,不自动召修复
deferToToothDx?: boolean; // 「建议拔除」场景专用:有同牙编码病种诊断 → 让位给该病种场景(避免双召)
polishImpliesRestoration?: boolean; // 缺失牙专用:缺牙位上的裸「抛光」= 修复体在位的证据(牙都没了,抛的是义齿)
treatedEvidenceFromEmrText?: boolean; // 本次动作是预防/复查类时,再审同次病历主诉/现病史找"已治疗"证据
}
/// §E gap 修正 flag 的单一真理源(按 primaryCode 查)。召回 SUB_SCENARIOS 与画像标签都引此。
......@@ -50,6 +51,7 @@ export const GAP_FLAGS_BY_PRIMARY: Record<string, GapCfgFlags> = {
excludeOrthoExtractionSites: true,
excludeCongenitalName: true,
polishImpliesRestoration: true,
treatedEvidenceFromEmrText: true,
},
// 「建议拔除」独立场景:有同牙编码病种诊断 → 让位给病种场景,不重复召(残根=K03、阻生=K01…)
EXTRACTION_RECOMMENDED: {
......@@ -277,7 +279,11 @@ export function buildGapCore(input: GapCoreInput): GapCorePieces {
const emrTextSql = Prisma.raw(
TREATED_EVIDENCE_EMR_FIELDS.map((f) => `COALESCE(emx.content->>'${f}', '')`).join(" || ' ' || "),
);
const treatedEvidenceBranch = evidenceTerms.length
// ⛔ **按场景开闸,不默认全开**。机制本身与场景无关(判据是牙位级的),但词表是拿
// 缺失牙的 59 条命中逐条人工核出来的 —— 「戴牙」蕴含"这颗牙的修复做完了",对 K08 成立;
// 对 K02 龋齿/K04 根尖炎是否同样成立**没有验过**(那些场景理由量 18 万+,导不出来复核)。
// 少召不报错,没验过就不开。要给别的场景开,先把该场景的命中全量导出人工过一遍。
const treatedEvidenceBranch = cfgFlags.treatedEvidenceFromEmrText && evidenceTerms.length
? Prisma.sql`
UNION
SELECT tvt AS t
......
......@@ -8,6 +8,7 @@
* 跑:
* pnpm test -- treated-evidence-from-emr-text
*/
import { GAP_FLAGS_BY_PRIMARY } from '../src/modules/clinical-gap/potential-treatment-gap.sql';
import {
TREATED_EVIDENCE_RESTORATION_TERMS,
TREATED_EVIDENCE_COMPLETION_RE,
......@@ -112,6 +113,13 @@ describe('表自身自洽', () => {
for (const t of TREATED_EVIDENCE_RESTORATION_TERMS) expect(cats).toContain(t.category);
});
it('🔴 ⛔ 只对缺失牙(K08)开闸 —— 词表是拿 K08 的命中人工核出来的,别的场景没验过', () => {
const on = Object.entries(GAP_FLAGS_BY_PRIMARY)
.filter(([, f]) => f.treatedEvidenceFromEmrText === true)
.map(([code]) => code);
expect(on).toEqual(['K08']);
});
it('三个正则都可编译', () => {
expect(() => new RegExp(TREATED_EVIDENCE_COMPLETION_RE)).not.toThrow();
expect(() => new RegExp(TREATED_EVIDENCE_INTENT_EXCLUDE_RE)).not.toThrow();
......
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