Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pac
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ai-tools
pac
Commits
c1e09831
Commit
c1e09831
authored
Oct 22, 2026
by
luoqi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
docs: archive Meyer and patient facts development records
parent
964fdd2e
Pipeline
#3859
failed in 0 seconds
Changes
9
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
627 additions
and
0 deletions
+627
-0
docs/_archive/2026-10-meyer-and-patient-facts/2026-10-17-meyer-imaging-adapter-local.md
+134
-0
docs/_archive/2026-10-meyer-and-patient-facts/2026-10-19-meyer-diagnosis-mapping.md
+87
-0
docs/_archive/2026-10-meyer-and-patient-facts/2026-10-19-meyer-open-facts-local.md
+70
-0
docs/_archive/2026-10-meyer-and-patient-facts/2026-10-19-open-patient-facts-test.md
+56
-0
docs/_archive/2026-10-meyer-and-patient-facts/2026-10-20-fact-content-field-contract-review.md
+0
-0
docs/_archive/2026-10-meyer-and-patient-facts/2026-10-20-meyer-open-facts-test.md
+57
-0
docs/_archive/2026-10-meyer-and-patient-facts/2026-10-21-open-content-source-time-test.md
+52
-0
docs/_archive/2026-10-meyer-and-patient-facts/2026-10-21-source-time-eight-hour-readonly-audit.md
+131
-0
docs/_archive/2026-10-meyer-and-patient-facts/README.md
+40
-0
No files found.
docs/_archive/2026-10-meyer-and-patient-facts/2026-10-17-meyer-imaging-adapter-local.md
0 → 100644
View file @
c1e09831
# 美亚影像补充采集:本地实现与验证
> 历史归档(2026-10-22):本文记录当时的实现、审核或验证情况,正文中的“未提交/未部署”等状态仅指原记录日期;不代表当前版本或运行状态。现行说明见本目录索引。
日期:2026-10-17。分支:
`codex/meyer-imaging-adapter`
,从
`main@1cafc8ae2df5a87d1d9d5ff01bb48c6c702b818f`
创建独立工作区。本次未提交、合并或部署。
## 实现
-
独立
`meyer-imaging`
CLI,默认只采集/留底/校验;
`--apply`
才连接明确指定的 PAC 数据库。
-
美亚认证、诊所分页、逐张病症查询均在适配器中;不注册到主服务、不修改主摄入游标。
-
显式诊所到 Friday tenantId/sourceUnit 映射,只匹配已有患者;不创建患者、不移动归属、不触碰其他宿主。
-
首次有效牙位分析转换为现有
`image_study`
和
`diagnosis`
,通过现有解析器、FactWriter 落成标准事实。来源
`image_ai`
,复用共享临床字典精确映射,不改画像或召回算法。
-
无分析完成状态/时间时不伪造 image_analysis;诊断证据时间采用检查时间,原始分析和时间依据保存在私有留底及事务原文。缺时间/空结果等待后续重试。
-
本期不做对账。成功的影像不复查、不自动更新或撤回;未完成可重跑固定窗口。原片不下载,临时 URL 不作为永久地址。
配置、运行方法与取舍见
[
适配器说明
](
../../../apps/pac-service/src/integrations/meyer/README.md
)
。
## 首轮模拟验证结果
| 检查 | 结果 |
|---|---|
|
`pnpm --filter @pac/service type-check`
| 源码和测试 TypeScript 检查通过 |
|
`pnpm --filter @pac/service build`
| Nest 构建通过 |
| 美亚适配器单元/HTTP 测试 | 13 项通过;实际 localhost HTTP,非仅 mock fetch |
| 独立 PostgreSQL 集成测试 | 6 项通过;包含完整 CLI apply 路线 |
| 现有影像分析与 canonical 时区回归 | 110 项通过 |
| 合计 | 4 套、129 项通过,单进程运行 |
测试覆盖标准影像及 K02 诊断落库、原始依据留存、时区与牙位、未知分析不制造阴性结论、重复运行不增版本、跨品牌同 ID 隔离、其他宿主不写入、未知患者拒绝、部分落库失败后恢复、状态锁、改绑拦截、分页数量变化/缺页、超时、HTTP 200 业务失败以及认证失效的一次重试。
数据库使用本地 PostgreSQL 内独立
`pac_meyer_ci_*`
数据库和临时角色,测试后已删除。首轮验证没有访问真实美亚、测试服务器或生产服务器。主目录原有未提交文档保持原状,本地应用未重启。
## 首轮待确认事项(真实联调更新见下)
1.
美亚部署地址、对应 SaaS 应用的读取凭据及诊所范围。PDF 与 SDK 的病症接口参数不一致,本实现按 PDF 带上 patientId。
2.
真实返回的时间和牙位格式;当前源时间按中国部署
`YYYY-MM-DD HH:mm:ss`
解析,不依据本机时区猜测。
3.
首期不承诺迟到分析自动追齐、完整变更同步或删除识别;须检查待处理计数再移动时间窗。
4.
该采集任务不自行重算;事实由现有、已启用的画像水位扫描消费。未来如需实时入队,单独增加既有队列的提交机制,不更改召回方案。
## 真实接口联调(2026-10-17 08:15 上海时间)
**结论:现有 SaaS 源码默认配置可读取真实美亚测试影像和分析;已在一次性本地数据库验证标准事实落库。未部署。**
### 配置与测试数据
-
使用
`friday-saas/emr`
中现有配置,地址
`https://re-pacs.myyun.com/api/v1`
;鉴权 HTTP 200、业务 code 200。凭据未复制进仓库。
-
只读查询 FridaySaaS 测试 MySQL(123.57.209.112:3309)中的
`emr.med_pacs_sync_record`
,核对患者主档和品牌、诊所归属。当前有效患者绑定涉及 4 个诊所。
-
在上述范围查询美亚:
`ba57…4c2b`
返回总数 8,
`7992…8e68`
返回总数 24;后者只取第一页 20 张用于找样本,未全量采集。其余两诊所返回业务 code 460,不能解释成“没有影像”。
-
样本为测试患者“患者01”,源患者 ID
`676698`
,诊所
`7992406f9e4b44c7ba3a67c8de368e68`
。患者主档和 PACS 同步记录均确认品牌
`c464d41cf2f8408187d8b5c525bc0369`
。组织树未查到该诊所名称,因此不猜测名称。
-
以上证明源码配置可以读取测试绑定对应的数据;尚未读取 SaaS 运行进程配置,不能据此保证部署环境没有配置覆盖。
### 真实采集与落库
仅运行该患者的固定入库窗口
`2026-10-16 15:51:31–15:51:33`
。美亚实际返回 2 张,已核对均属于同一患者;其中影像
`369391900555579392`
有 11 条牙位分析,另一张分析为空。
| 验证 | 实际结果 |
|---|---|
| PDF 参数(含 patientId)查询分析 | 业务 code 200,返回 teeth / diagnosis / description |
| 独立 CLI 采集 | 2 张;1 张有效分析、1 张待处理、0 失败 |
| 本地标准事实 | 1 条 image_record + 11 条 diagnosis_record,12 条事务 |
| 信号示例 | 36/37 根尖周炎 → K04,23 埋伏牙 → K01;来源 image_ai,保留影像关联 |
| 重复运行 | 仍为 12 条事实,全部 version=1;已完成影像跳过 |
| 空分析 | deferred=1,无诊断事实;CLI 退出 2 表示仍有待处理,不是全量完成 |
| 画像与召回 | 均为 0;本次不启动队列或计算任务 |
| 清理 | 临时本地数据库和角色已删除;主库及本地应用未变动 |
真实返回的
`modality=IMAGE_2D`
曾被直接透传,导致 PAC image_record 枚举校验拒绝。适配器现将无法明确对应的供应商类型映射到
`other`
,完整原值保存在原始证据;没有凭二维图片类别猜测全景片等类型。修复后真实采集、落库和重复运行全部通过。
共享字典目前精确匹配到 5 条带 K 编码的牙位事实,其余 6 条保留原文、code=null。例如“龋病”未命中现有精确字典;本次没有扩充疾病推断或改变召回规则。综合文本“慢性牙周炎”仅留原始依据,未额外解析成诊断。事实写入成功不等于所有分析术语都已参与召回。
时间测试发现:以返回的秒级时间同时作为开始和结束,接口返回 0;前后扩展一秒则返回 2 张。底层时间精度或边界行为尚不能确定,不能用零宽窗口作为可靠采集方式。
### 回归与证据
-
4 套测试、130 项通过(新增供应商 IMAGE_2D 到 PAC 事实校验的回归用例);Nest 构建通过。
-
真实原文、绑定、私有采集状态和数据库验证结果保存在本机
`/tmp/pac-meyer-live-private/`
(私有目录),未入 Git;该目录是临时联调证据,不作为长期业务存储。
-
本次只对源端执行鉴权和查询。没有修改 SaaS/美亚数据,也没有向测试或生产 PAC 写入数据。
## 原片访问验证(2026-10-17 13:10 上海时间)
继续使用上述测试患者的同一张影像,只查地址与读取 1 字节,不下载完整原片。
-
`imageId=369391900555579392`
;
`imageOssId=369391906454630400`
。后者是美亚接口使用的文件标识,并非 OSS object key。
-
请求
`POST /api/v1/imaging/external/images/urls`
,参数为原影像
`clinicId`
和
`ossIds: [imageOssId]`
,HTTP 200、业务 code 200、
`found=true`
。
-
返回阿里云 OSS 签名 URL,域名
`myy-pre.oss-cn-beijing.aliyuncs.com`
;对象路径形如
`prod/clinic/<美亚内部诊所ID>/20261016/<imageId>/05170433.png`
。不能从文件 ID 直接推导路径,也不能仅凭 bucket 名或路径中的 prod 判断业务环境。
-
本次返回过期时间
`2026-10-17 13:40:36`
,距查询约 30 分钟。应按 expiresAt 刷新,不能硬编码文档默认 12 小时。
-
对签名地址发 HEAD 返回 403;改用 GET +
`Range: bytes=0-0`
返回
**206**
,
`Content-Type: image/png`
,
`Content-Range: bytes 0-0/1270699`
。实际读取
**1 字节**
;验证了该地址可读,未下载完整 1,270,699 字节文件。HEAD 失败不能用来断言 GET 签名链接失效。
-
这是本样本的“原图文件”PNG,不代表验证了 DICOM 或 CT 切片;CT 需按接口返回的 ctSlices 文件 ID 分别获取地址。
结论:现有美亚应用权限已经足够通过文件 ID 换取原图访问地址,无需先拿阿里云账号权限。PAC 原始摄入证据已留存此文件 ID;目前独立适配器尚未提供前端文件地址刷新接口。若未来绕过美亚直读 OSS,仍需保存/获得 bucket 与完整 object key,不能仅凭 imageOssId。
私有请求结果和验证摘要位于
`/tmp/pac-meyer-live-private/file-url-response.json`
、
`file-url-verification.json`
,签名 URL 不写入文档或仓库。
## 增量运行优化(2026-10-17)
继续在原独立工作区开发,没有提交、合并或部署;本轮不启动真实美亚常驻采集。
-
新增
`--tick`
:一轮独立任务,持久化私有 cursor。每轮最多推进一小时,距离当前时间保留一分钟,窗口重叠一分钟;失败不推进,持久化待分析后可推进。
-
新增
`--watch`
:每轮结束后等待五分钟。正常停止信号会收尾并释放锁;失败退出并保留状态。默认未启用,未安装系统定时器。
-
新增私有 pending/:延迟分析与部分落库失败可以重试。每轮最多 20 项、指数退避到一小时,不自动丢弃。重试窄窗重新核对影像身份;已绑定患者发生变化时拒绝写入。未提供入库时间的待处理项需要人工处理。
-
影像成功后仍不复查分析,不增加历史对账、撤回或自动改绑。
-
新增
`--image-files=<imageId>`
:针对已采集影像,通过 imageOssId 获取原图临时 URL,保存到私有 access 文件。终端不输出签名、不下载文件;不提供公开 Web 接口,不替代患者权限检查。
-
同一轮中不同窗口共享美亚鉴权缓存,避免每个待处理影像都重新申请令牌。
验证包括:迟到分析跨窗口补入、失败不推进水位、窗口重叠与重复写入、患者改绑拦截、重试限额与退避、preview 禁止推进水位、文件 ID/诊所检查、签名不进入控制台,以及完整 CLI tick 经真实本地 PostgreSQL 写入两次而不重复。本轮覆盖 5 套、136 项测试(全套 135 项通过后新增限额用例,相关 20 项复跑通过),TypeScript 检查通过。原有影像分析与时区测试继续通过。临时数据库和角色已删除。
运行参数与状态文件说明见适配器 README。旧状态目录需先重跑原窗口生成 pending 后再启用定时模式;生产启用前仍需确认实际部署配置和诊所到品牌映射。
## 保守限额与断点恢复(后续更新,以本节为准)
默认值已改为:轮间隔 15 分钟、新扫描记录每轮最多 100 条、待处理重试最多 10 张、串行请求间隔 500ms;均可配置。新扫描分页查询默认每轮最多 10 页,单个待处理项窄窗查询也受页数上限控制。轮间隔在本轮收尾后计时。
新增 scan-progress(固定窗口/诊所/页码/页内行/页原文)和 scan-ledger(已完成页的影像 ID)。达到限额只保存断点、不推进窗口水位;下轮继续。数量、首页或当前缓存页身份变动时重扫当前诊所;跨页重复阻止窗口完成。签名 URL 更新不触发窗口重置。文件写入先 fsync、原子 rename、再 fsync 目录。
watch 对请求、鉴权或数据库异常记录失败次数,按默认 15/30/60 分钟退避,依赖恢复后继续。停止信号等当前一轮收尾。正常宿主服务不参与采集循环;数据库仍是落库依赖。进程退出/OOM/机器重启需要外部守护,提供 service 示例(Restart=on-failure、持久状态目录、资源约束),本次未启用。明确死亡的本机进程锁可自动回收,存活、其他机器、未知 owner 或锁回收过程本身被中断的情况不自动抢锁。
存储没有新增数据库表:采集运行状态和原始快照存独立持久目录;业务数据复用 patient_transactions / patient_facts,patients 仅查询。目录不能放临时盘,需备份;当前实现是单机单写者。目录丢失/损坏、永久权限或归属错误需要人工处理,不能承诺自动修复数据。
新测试覆盖跨轮页内续跑、重启恢复、限额、续签 URL 不影响断点、offset 插入和跨页重复、第二页接口故障恢复、watch 退避恢复、死亡进程锁回收与存活锁保护。全套 6 套 141 项通过后增加跨页重复用例并单独复跑;最终覆盖 143 项(含新增的单轮看门狗用例)。真实本地 PostgreSQL 集成保留,临时库和角色已清理。
这里只保证自身限额、重复处理和中断不会主动跳过数据。美亚无快照/更新游标,任意历史回填、已完成窗口外的修改和撤回仍需要将来的对账能力,不能由有限重叠窗口提供绝对保证。
补充单轮卡住保护:watch 的 roundTimeoutMs 默认 10 分钟,超时明确退出,交给外部守护从断点重启;不使用 Promise.race 后继续开新轮,避免旧请求仍在写入。看门狗触发及正常结束清理计时器已增加测试。
## 自动诊所/品牌映射(2026-10-17)
-
已核对 PAC 组织树代码:组织关系由业务记录诊所和关联患者品牌派生,名字典仅存名称。现有树的 LIMIT 1 抽样不能发现冲突,本采集器采用独立只读解析,检查全部不同候选;不改主组织树或召回流程。
-
配置改为 clinicIds;禁止手填 tenantId/sourceUnit。缺失、跨品牌、跨租户、孤立关联均拒绝采集;排除美亚补充产物,避免自我确认。
-
每轮重新解析。既有状态目录绑定映射和数据库,变化时停止,保留快照/断点待核查。
-
本机 pac 数据库只读检查:有 1,141,991 条业务记录,但 Friday 宿主对应业务记录为 0;两家此前美亚测试诊所也没有可解析的本地关系。因此不声称真实映射已验证,不自动创建关系或导入患者。
-
所有实际写入验证在临时隔离 PostgreSQL 数据库执行;不访问、修改或部署测试/生产环境。
-
本次验证:6 个测试套件、144 项测试通过;service 类型检查与构建通过。隔离验证数据库已删除。配置示例和 README 已同步更新,未提交、未部署。
docs/_archive/2026-10-meyer-and-patient-facts/2026-10-19-meyer-diagnosis-mapping.md
0 → 100644
View file @
c1e09831
# 美亚分析标签 → PAC K 码:映射核对与风险
> 历史归档(2026-10-22):本文记录当时的实现、审核或验证情况,正文中的“未提交/未部署”等状态仅指原记录日期;不代表当前版本或运行状态。现行说明见本目录索引。
2026-10-19 ·
`codex/meyer-imaging-adapter`
· 本地改动,未提交、未部署
本轮沿用现有美亚逐张分析接口,只核对
`teeth[].content`
的整词映射。不接入尚未实现的回调或批量接口,不改患者身份、采集调度和召回规则。
## 结论
用户清单共 34 项,去掉完全重复的 6 项后为
**28 个名称**
;“龋病 / 牙龋坏”归同一概念后为 27 类。保留原始名称与牙位,不因同一 K 类别而合并不同病变。
-
**补充 4 个名称**
:缺牙→K08,龋病 / 牙龋坏→K02,牙折裂→K03。
-
**保留 9 个现有映射**
:多生牙、乳牙滞留、埋伏牙、残根、残冠、根尖周炎、楔状缺损、根分叉病变、牙体缺损。
-
**15 个名称暂不定 K 码**
:原始所见照常保留。其中裸词“智齿”从本适配器原来的 K01 改为空码,其余维持空码。
**这里的 K 码是 PAC 现有业务分类,不是完整 ICD 编码,更不代表医生确诊或治疗指征。**
PAC 当前按 K 类别组织治疗机会,补码会改变哪些影像信号可能进入画像和召回,不能只追求覆盖率。
## 逐项核对
已对比本地记录的
`origin/main@b7901c9`
:共享诊断字典与业务 K 类别定义没有差异;未将主线其他改动合入当前工作区。
“原映射”以本工作区的美亚适配器为准:只查共享字典精确词,不使用通用关键词规则。
`—`
表示保留原文、
`code=null`
,不表示正常。
| 去重名称 | 原映射 | 本轮映射 | 判断与风险 |
|---|---|---|---|
| 智齿 | K01 | — | 识别到第三磨牙不等于阻生。共享字典依据宿主医生录入习惯归 K01,不能直接套给影像标签;明确“阻生智齿”仍走原映射 |
| 缺牙 | — | K08 | 对齐既有“缺失牙”。不推断缺失原因、是否已修复或是否适合种植;后续仍受现有牙位、年龄和治疗证据规则约束 |
| 多生牙 | K00 | K00 | 沿用发育/萌出异常类别,不据此判定需要拔除 |
| 牙槽骨吸收 | — | — | 影像所见不能直接补成活动性牙周炎;归 K05 会把所见送入“牙周炎未治疗”路径 |
| 残根 | K03 | K03 | 沿用 PAC 业务口径;不等同标准 ICD 子码,也不表示一定无法保留 |
| 残冠 | K03 | K03 | 同上,是否可保存仍需临床判断 |
| 埋伏牙 | K01 | K01 | 沿用阻生/埋伏类别;只作为影像信号 |
| 乳牙滞留 | K00 | K00 | 沿用发育/萌出异常类别;不把正常换牙期直接理解为治疗需求 |
| 龋病 | — | K02 | 与既有“龋齿/龋坏”类别一致,不推断深浅或治疗方式 |
| 修复体牙冠 | — | — | 修复物存在,不等于不良修复体、待修复疾病或完整治疗记录 |
| 种植体 | — | — | 种植体存在,不等于缺牙、种植体周围炎或种植疗程完成 |
| 充填体 | — | — | 充填物存在,不等于继发龋或充填治疗在本次影像时完成 |
| 根尖周炎 | K04 | K04 | 沿用现有映射。影像来源须保留,不能据此区分初治、再治疗、治疗后愈合或直接决定根管治疗 |
| 牙龋坏 | — | K02 | 与“龋病”同一类别,原词留存 |
| 根充 | — | — | 根管充填痕迹,不等于当前牙髓病,也不能伪造治疗完成时间 |
| 金属冠 | — | — | 属于修复体,不能与“不良修复体”混同 |
| 嵌体 | — | — | 属于修复体,不是疾病名称 |
| 牙髓石 | — | — | 通用关键词会因“牙髓”命中 K04,但当前 K04 召回是牙髓/根尖问题未做根管,不能直接套用 |
| 楔状缺损 | K03 | K03 | 沿用牙体损伤类别;不补严重度和必需治疗结论 |
| 牙折裂 | — | K03 | 对齐 PAC 已有“牙折/隐裂/冠折/根折”的业务类别;不推断折裂部位、外伤编码或保留价值 |
| 种植体周围炎 | — | — | 是有临床意义的标签,但现有自然牙牙周类别及治疗解除逻辑不能直接代表种植体疾病;保留待评估,不降成“无问题” |
| 牙周牙髓联合病变 | — | — | 单码 K04 或 K05 会丢掉另一部分;机械拆两条又会改变召回及解除逻辑,本轮不强行归类 |
| 根分叉病变 | K06 | K06 | 沿用 PAC 现有牙龈/牙槽嵴业务类别,不声称这是标准 ICD 对应,也不在此改全局分类 |
| 颌骨病变 | — | — | 名称过宽,不能猜为囊肿 K09 或某一确定疾病;保留原始异常所见 |
| 牙体缺损 | K03 | K03 | 沿用硬组织损伤类别,不推断是否需要充填、冠修复或拔除 |
| 骨结构不良 | — | — | 缺少部位、病因与标准含义,不能猜为牙周病或颌骨病 |
| 骨岛 | — | — | 不具备映射到当前治疗召回类别的充分依据,保留所见 |
| 牙齿矫正 | — | — | 治疗/状态类表述,不等于错颌诊断;归 K07 可能把在矫正者识别为“未启动正畸” |
完全重复项:缺牙、多生牙、残根、残冠、种植体、根尖周炎,均出现两次。金属冠是修复体牙冠的更具体描述,保留来源粒度,不当作完全相同的词删除。
## 为什么不直接打开共享关键词匹配
共享关键词已能命中缺牙、龋病、牙龋坏、牙折裂,但同样会让“牙髓石”和“牙周牙髓联合病变”命中 K04。共享精确字典还会让裸词“智齿”命中 K01。
代码核对显示,现有治疗召回按诊断 K 码匹配,
`code_source=image_ai`
并不是一层独立的医生确认门槛。因此本轮仅在美亚适配层增加整词规则和所见保护,
**不扩大共享字典影响所有宿主的范围,也不对否定、可疑或复合文本做含词推断。**
K03 的残根/残冠、K06 的根分叉病变等是已有业务口径;若以后需要标准 ICD 子码或更精确的影像风险分析,应将“来源标签、标准临床编码、业务用途”分开,不能靠继续往一个大类里塞词解决。
## 本地变更与验证范围
-
`diagnosis-mapping.ts`
:美亚专用整词补充与 15 项空码保护;其余继续共享精确字典。
-
`mapper.ts`
:调用独立映射函数;原文、牙位、影像关联与
`image_ai`
来源保留。
-
已留底 bundle 按旧快照重试,已成功影像仍跳过。此次补码不会自动修正存量,也不删除状态目录或绕过事务哈希检查。
-
本地 6 套测试、121 项通过,覆盖全部 28 项、可疑/否定/复合词、原文留存、共享字典隔离及原有采集/断点/调度回归;服务源码和测试 TypeScript 检查通过。本轮未执行 PostgreSQL 落库测试。
-
不访问服务器,不修改测试或生产数据,不启动常驻采集、画像或召回任务。
## 核对依据
项目实现:
-
[
共享诊断字典
](
../../../apps/pac-service/data/_shared/dict/diagnosis-kcode.yaml
)
:精确映射与含词规则。
-
[
美亚映射
](
../../../apps/pac-service/src/integrations/meyer/mapper.ts
)
、
[
本轮专用映射
](
../../../apps/pac-service/src/integrations/meyer/diagnosis-mapping.ts
)
:本条采集路线实际使用的规则。
-
[
业务类别及纠偏
](
../../../packages/types/src/canonical-codes.ts
)
:残根/残冠等 PAC 业务口径。
-
[
治疗召回场景
](
../../../apps/pac-service/src/modules/plan/engine/scenarios/treatment-initiation-recall.scenario.ts
)
、
[
诊断缺口查询
](
../../../apps/pac-service/src/modules/clinical-gap/potential-treatment-gap.sql.ts
)
:K 码对治疗机会的实际影响。
临床边界参考(用于识别映射风险,不作为自动确诊依据):
-
[
ADA:智齿
](
https://www.ada.org/sitecore/content/ADA-Organization/ADA/MouthHealthy/home/all-topics-a-z/wisdom-teeth
)
:智齿与发生阻生或病变的智齿不是同一概念。
-
[
EFP:牙周炎诊断流程
](
https://www.efp.org/fileadmin/uploads/efp/Documents/Campaigns/New_Classification/Guidance_Notes/report-02b.pdf
)
:影像骨丧失还需结合临床检查,不直接等同待治疗牙周炎。
-
[
EFP/AAP:种植体周围疾病共识
](
https://doi.org/10.1002/jper.17-0739
)
:种植体周围炎有自身的临床和影像判断依据,不能机械套用自然牙治疗路径。
docs/_archive/2026-10-meyer-and-patient-facts/2026-10-19-meyer-open-facts-local.md
0 → 100644
View file @
c1e09831
# 美亚适配器与开放患者接口:本地整合验收
> 历史归档(2026-10-22):本文记录当时的实现、审核或验证情况,正文中的“未提交/未部署”等状态仅指原记录日期;不代表当前版本或运行状态。现行说明见本目录索引。
2026-10-19 ·
`codex/open-patient-facts`
· 未提交、未部署
## 范围
将
`codex/meyer-imaging-adapter`
工作区的 24 个新增文件及两个 CLI 脚本入口整合到当前工作区。原分支上的功能尚未提交,因此此次是文件整合,不是已完成 Git 分支合并。原美亚工作区与主目录的工作区状态及未提交文件哈希前后相同。
初次整合时,适配器运行代码与原工作区逐文件一致;后续本工作区增加影像内分析快照,见末节。继续独立运行,不注册到主应用,不启动常驻采集;保持
`image_record + diagnosis_record(code_source=image_ai)`
,不新增
`image_analysis_record`
,不改摄入标准、画像或召回规则。
## 完整链路
新增验收在既有
`meyer-imaging-postgres.spec.ts`
中,使用本地 HTTP 美亚模拟响应、真实 CLI、真实 PostgreSQL、真实应用鉴权和查询控制器。端口随机分配,数据库和角色为一次性
`pac_meyer_ci_*`
,连接数限制为 2,结束后清理;不连接测试或生产环境,不使用真实应用密钥。
| 验证 | 结果 |
| --- | --- |
| 组织映射 | 从既有 Friday 业务记录自动解析诊所与品牌;冲突拒绝继续 |
| 采集与标准化 | 美亚鉴权、影像查询、病症查询 → 私有留底 → 标准解析与事实落库 |
| 数据产出 | 1 条影像 + 2 条影像来源诊断,无独立分析报告 |
| 开放鉴权 | appId/appSecret 换应用令牌成功;缺令牌查询被拒绝 |
| 开放返回 | 病历号查询返回匹配患者,公开字段通过响应 schema 校验 |
| 影像关联 | diagnosis.content.sourceImageExternalId 对应 image.content.externalId |
| 编码与时间 | 龋齿为 K02,可疑龋保留空码;诊断取检查时间,影像取影像创建时间,均为 UTC |
| 出站范围 | 不返回私有供应商原始响应、OSS ID 或临时签名地址(后续允许标准化的分析结论与描述,见末节) |
| 隔离 | 同宿主不同品牌的同号患者分开返回,未采集品牌无事实;另一宿主令牌查不到本宿主数据 |
| 重复运行 | 增量重复及固定窗口重放均不新增事实,API 返回保持一致 |
| 副作用 | 画像与召回记录数为 0 |
本次源端使用可重复的模拟响应,未再次调用真实美亚接口;此前真实联调记录见原美亚验收文档,不能视为本次实测。
## 验证结果
-
10 套、148 项适配器与开放接口回归通过。
-
3 套、118 项数据库完整链路、既有分析解析和源时区回归通过。
-
服务源码与测试 TypeScript、文档站类型检查通过。
-
单页 API 文档保留 11 类事实,在诊断部分补充影像分析读取说明及关联示例;示例通过真实映射、解析、返回层校验。
-
主目录和美亚工作区未变;未重启业务服务;独立文档站使用 3112。最终页面验证时,原文档预览进程达到 8 GB 堆限制退出,尝试 3 GB Webpack 预览仍内存不足,已保留原缓存到 /tmp 并恢复 Turbopack,堆上限 4 GB;仅调整当前工作区启动命令,未修改项目运行配置。
首轮发现新测试的可空类型声明问题,已显式处理;静态源样本第三轮超出增量窗口被正确拒绝,重放验收改为同一固定窗口,不修改采集器的窗口检查。
最终 3112 页面已恢复 HTTP 200,实际 HTML 核对为 11 类事实,含新增影像分析关联示例。
## 本次补充:影像 content.analysis
本工作区新增通用
`ImageEmbeddedAnalysisSchema`
,由影像 canonical 与事实 content 共用。新采集的美亚影像增加可选
`analysis`
:
-
`source`
:分析来源,美亚为
`meyer`
。
-
`summary / description`
:来源综合结论、描述原文。
-
`analyzedAt`
:真实分析完成时刻,统一 UTC;美亚没有提供,留 null。
-
`findings[]`
:
`name / toothPosition / code`
,复用原有去重及诊断码映射;未知码保留 null。
原有
`diagnosis_record`
的身份、代码映射、时间、落库路径不变;不生成新的
`image_analysis_record`
。影像分析与关联诊断表达同一批病症,不重复计数。
`finding`
原字段保留,不被分析结论替换。未声明的供应商扩展字段在分析标准化时移除。
### 5i5ya 边界
共用同一可选结构,但现有
`image_finding.yaml`
只有
`emr_id`
病历级关联,没有可靠的单张影像标识;
`image.yaml`
也不输出 analysis。本次不根据患者或病历猜配到某张影像,不改 5i5ya 映射。缺失/null 不代表源端没有分析数据。
### 兼容性与验证
-
旧影像缺失 analysis 时不增加默认字段;旧 bundle 按原快照重试,已应用快照仍跳过。本次没有历史补写或状态清理。
-
152 项适配器与开放接口回归通过,覆盖标准结构、未知码、去重顺序、旧快照、文档完整性和示例。
-
119 项隔离数据库及既有分析/时区回归通过:本地模拟美亚 HTTP → 真实 CLI → 真实 PostgreSQL → 应用令牌 → 开放患者查询。
-
实测 1 条带 analysis 的影像 + 2 条既有诊断;数据库和 HTTP 返回 analysis 相同;重复采集不增版本;跨品牌和跨宿主隔离仍成立;画像及召回记录数为 0。
-
服务源码与测试类型检查、共享类型构建、文档站类型检查通过。首次检查发现新测试把 JSON 联合类型直接当对象读取,已改成对象断言后复查通过。
本次未调用真实美亚接口;未部署、未提交,未修改主目录和原美亚工作区,未重启业务服务。临时数据库与角色已清理;文档仍在当前工作区 3112 端口。
最终收尾:影像与文档相关的 34 项用例再次通过(包含 UTC 时间归一化);3112 文档预览热更新触及 4 GB 堆上限退出后,仅恢复当前工作区的文档进程。页面重新返回 HTTP 200,实际 HTML 包含 analysis 字段表、完整嵌套示例和避免重复计数说明。业务服务未重启。
docs/_archive/2026-10-meyer-and-patient-facts/2026-10-19-open-patient-facts-test.md
0 → 100644
View file @
c1e09831
# 开放患者查询:测试环境验收
> 历史归档(2026-10-22):本文记录当时的实现、审核或验证情况,正文中的“未提交/未部署”等状态仅指原记录日期;不代表当前版本或运行状态。现行说明见本目录索引。
日期:2026-10-19。仅测试环境发布,生产未操作。
## 版本与部署
-
功能提交:
`7bdc1a5`
,
`codex/open-patient-facts`
。
-
测试合并:
`1e0c92f`
,本地与远端
`test`
已同步。
-
`main`
保持
`b7901c9`
;未合入 main,未访问生产服务器。
-
测试机
`/root/pac`
的后端、工作台、文档站已部署同一版本。
-
迁移
`20261019170000_open_patient_facts`
已执行,全部迁移完成;运行镜像与构建镜像一致,
`/health`
正常,工作台与文档站 HTTP 200。
-
回退:测试机
`/root/pac-release-backups/20261019-open-patient-facts/`
,包含旧版本、迁移前结构及部署日志;旧镜像以
`rollback-open-facts-20261019`
标签保留。新增列和索引不需回删即可回退旧代码。
-
发布前没有 running 摄入任务或数据库长查询。主目录未提交文件及本地业务服务未改动;独立文档站仍使用 3112。
## 本地复核
9 套、128 项测试通过(含真实 PostgreSQL + HTTP 8 项);源码/测试类型检查、文档站类型检查与文档示例校验通过。修改文件 ESLint 无错误,27 项既有警告已在本地验收文档说明。
测试合并无冲突。合并结果与功能分支在本次后端、共享类型、迁移代码上一致;test 中原有 FridayAI 测试改动保留,未发布 FridayAI。
## FridaySaaS 真实应用联调
使用既有测试环境 FridaySaaS 的 appId/appSecret,无新增应用、无密钥轮换,密钥与令牌不记入本文。
-
公网
`https://pac.jarvismedical.asia/pac/v1/auth/token`
:未授权时返回
`10107`
,验证默认关闭。
-
仅对测试 Friday 宿主执行
`grant-facts-read friday`
;
`friday=true`
、
`jvs-dw=false`
。
-
开通后返回
`code=0`
、Bearer 令牌、有效期 3600 秒,不含登录 code/refreshToken。
-
错误密钥
`10101`
;空/null user
`10002`
;无令牌、篡改令牌
`10106`
;空查询和未知参数
`10002`
。
-
无匹配返回
`items: []`
;查询另一个宿主的独有病历号返回空数组。
-
原 user 换票正常,仍返回 code/accessToken/refreshToken;用户令牌调用新查询返回
`10106`
,应用令牌调用工作台患者时间轴也返回
`10106`
。
## 真实患者与数据库核对
| 测试病历号 | API 事实 / 库内当前有效事实 | 画像 | 可解析关系人 | 服务内查询耗时 |
| --- | --- | --- | --- | --- |
|
`PE0A000868`
| 121 / 121 | 有 | 6 | 44 ms |
|
`PE0A000832`
| 43 / 43 | 有 | 1 | 39 ms |
|
`PE0A002965`
| 34 / 34 | 有 | 1 | 40 ms |
逐条核对事实主体与类型集合,并检查 PAC/宿主患者 ID、关系人范围、手机号掩码、profile 已合入 patient、输出结构以及多条件交集查询。
样本覆盖预约、接诊、病历、诊断、治疗、影像 6 类事实。其他类型由本地 17 类内容示例覆盖,不能据此宣称测试宿主已有全部类型。
公网测量(含本机网络耗时):取令牌 1218 ms;病历
`PE0A000832`
查询 1307 ms、43 条事实;
`PE0A000868`
查询 1693 ms、121 条事实,均返回画像。服务内上述耗时为本次样本测量,不代表并发压测或 SLA。
## 文档与边界
文档站 API spec 的 servers 已核对为
`https://pac.jarvismedical.asia`
,新参考页面标题已核对为“查询患者资料与事实”。
本接口是宿主全范围只读能力,实际使用者权限由宿主后端检查;未知数据保持空值,画像读取已有版本,不触发重算。本次没有回放摄入、重算画像或召回。
验收脚本最初以不存在的
`/auth/me`
作工作台拒绝探针,得到
`10004`
;改用实际
`/patients/:id/timeline`
后验证通过。这是验收路径修正,未修改业务代码。
授权 CLI 在退出时打印了组织预热取消警告;授权已成功,后续实际用户换票、患者查询与服务健康均验证正常。
docs/_archive/2026-10-meyer-and-patient-facts/2026-10-20-fact-content-field-contract-review.md
0 → 100644
View file @
c1e09831
This source diff could not be displayed because it is too large. You can
view the blob
instead.
docs/_archive/2026-10-meyer-and-patient-facts/2026-10-20-meyer-open-facts-test.md
0 → 100644
View file @
c1e09831
# 开放接口精简与美亚分析:测试环境验收
> 历史归档(2026-10-22):本文记录当时的实现、审核或验证情况,正文中的“未提交/未部署”等状态仅指原记录日期;不代表当前版本或运行状态。现行说明见本目录索引。
2026-10-20(发布跨过午夜)。仅测试环境发布;生产未访问、未部署。
## 版本与部署
-
功能提交:
`355a755`
(
`codex/open-patient-facts`
)。
-
test 合并:
`6c3f5f8`
;本地、远端及测试机一致。main 保持
`b7901c9`
。
-
后端、工作台、文档站均发布成功,运行镜像与构建镜像一致,容器重启次数均为 0。
-
`/health`
正文 status=ok;工作台与文档站可访问;58 个迁移全部完成,本次无待执行迁移。
-
发布前没有 running 摄入任务或超过 30 秒的活动数据库查询。
-
回退资料:测试机
`/root/pac-release-backups/20261019-meyer-open-refinement/`
,含旧 HEAD、旧镜像记录和部署日志。三个旧镜像均保留
`rollback-meyer-open-20261019`
标签。
## 验证范围
发布前新增复核:16 套 278 项回归及隔离 PostgreSQL + HTTP 的 10 项验收通过。首次复用旧临时库时发现它已被先前验收删除,重新创建一次性隔离库后通过并清理,未使用开发库代替。上一轮影像完整链路的 119 项回归、源码/测试类型检查、共享类型构建与文档类型检查也已通过。
合并没有冲突;test 与功能分支在本次 service/web/types/docs 范围完全一致。主目录未提交文件、原美亚工作区和本地业务服务保持原状;仅移除了此次创建的干净临时合并工作区,两个功能工作区均保留。
## 真实美亚采集
沿用现有美亚测试读取配置;从测试 PAC 既有宿主记录自动解析诊所、租户与品牌,核对患者归属后才写入。没有人工创建患者或修改组织映射。
-
样本病历号:
`F001000001`
(此前已核实的美亚测试患者)。
-
限定窗口:北京时间
`2026-10-16 15:51:31–15:51:33`
,仅 1 家诊所。
-
预览:2 张影像,1 张取得有效分析,1 张分析为空;failed=0。
-
应用:新增 1 条
`image_record`
与 11 条
`diagnosis_record`
。
-
`image_record.content.analysis`
含来源、综合结论、描述及 11 条 findings;analyzedAt=null,不伪造完成时间。
-
findings 与关联诊断逐条匹配;数据库 analysis 与开放接口返回完全一致。
-
重放:applied=0、alreadyApplied=1、deferred=1、failed=0;12 条事实均仍为 version=1,没有重复写入。
CLI 退出码 2 表示仍有待处理影像,不是本次落库失败。空分析影像保留在 pending 中,没有作为“分析正常”写入。本次只跑限定范围的手动验收,未启动 watch、全量扫描或常驻采集。采集状态与凭据位于测试机
`/root/pac-meyer-test/`
,目录权限 700、文件仅 root 可读;后续补拉须继续使用该状态目录,不得清空强制重跑。
没有改写既有诊断规则、历史事实或手动重算画像/召回。5i5ya 仍因缺乏单张影像可靠关联而不填 analysis,现有诊断摄入保持原样。
## 真实 FridaySaaS 鉴权与查询
使用用户此前提供的现有测试 appId/appSecret;未新建应用、未轮换密钥、未扩大权限。临时本地凭据文件验证后删除,密钥/令牌不记入本文。
通过 17 项鉴权/查询检查:正确凭据、错误密钥、空/null user、缺失/伪造令牌、空/未知参数、无匹配、组合精确查询、宿主隔离及原 user 换票。用户令牌不能调用应用查询,应用令牌不能访问工作台患者时间轴。FridayAI/HMAC 兼容性由本地集成回归验证,本次未部署 FridayAI。
四位患者逐条比对事实版本 ID 与类型集合,并核对关系人归属、患者 PAC/宿主 ID、手机号脱敏和精简后的字段;persona 为标签数组,已排除的内部属性不返回。
| 病历号 | API / 库内有效事实 | 关系数 | 本机回环 HTTP 查询耗时 |
| --- | --- | --- | --- |
|
`F001000001`
| 60 / 60 | 0 | 125 ms |
|
`PE0A000868`
| 121 / 121 | 6 | 411 ms |
|
`PE0A000832`
| 43 / 43 | 1 | 157 ms |
|
`PE0A002965`
| 34 / 34 | 1 | 97 ms |
公网取令牌成功,3 个样本查询均成功(约 0.8–1.0 秒,含本机网络;只是本次样本,不代表并发 SLA)。
`F001000001`
的公网响应也含美亚 analysis。
## 文档
[
测试环境 API 参考
](
https://pac.jarvismedical.asia/docs/api/open/PatientFactsLookupController_lookup
)
已更新。实际页面核对 analysis 字段表和嵌套示例;两个旧 integration 链接均返回 308 到单页 API 参考。OpenAPI Server URL 为
`https://pac.jarvismedical.asia`
。
docs/_archive/2026-10-meyer-and-patient-facts/2026-10-21-open-content-source-time-test.md
0 → 100644
View file @
c1e09831
# 开放患者查询与来源时间:测试环境验收
> 历史归档(2026-10-22):本文记录当时的实现、审核或验证情况,正文中的“未提交/未部署”等状态仅指原记录日期;不代表当前版本或运行状态。现行说明见本目录索引。
范围:仅测试。生产未访问、未部署;历史数据未回填。用户追加确认将工作区中的来源创建时间、退费更新时间和时区校验一起提测。
## 发布范围
-
功能分支
`codex/open-patient-facts`
:
`b502e1b`
。
-
test 合并:
`5b80c04`
。保留 test 原有美亚批量分析、患者归属校验和文件引用能力;合并处增加
`fileRefs`
的嵌套白名单,未把 test 合回 main。
-
开放查询:字段及嵌套扩展按白名单;关联仅使用本事实绑定且宿主/租户/患者/诊所一致的来源证据;病历 11 个段落统一成可读文本。
-
真实旧病历补充兼容:5i5ya 牙位编辑器的象限选择与可读牙位一致时去除重复状态;序列化备份不是正文或牙位来源,不据其恢复已取消选择。未知正文结构仍明确失败。
-
来源时间:新增可空
`source_created_at`
,只在正常新事实版本写入;来源记录的时间不冒充诊断动作时间。保留
`source_updated_at`
;修正退费投影丢失 updated_date;增加归一后时间校验和影像分析嵌套时间归一。
-
没有新增 source_created_at_basis。原有 received_at 保持。
## 本地验证
-
功能工作区:开放接口 216 项回归、时间相关 210 项回归通过;发现真实旧病历格式后补了兼容回归。
-
合并结果:20 套单元测试共 453 项最终通过。初跑 449 项通过,4 项美亚持久化/恢复用例触发本机磁盘同步时限;延长测试运行时限后,200 张持久化用例与恢复套件均通过。业务代码和提交中的测试时限没有因此修改。
-
合并结果隔离 PostgreSQL:来源时间 + 开放查询 13 项、美亚采集落库与开放查询 16 项通过;旧开放鉴权 HTTP 验收 10 项通过。
-
另补文件引用嵌套白名单测试;合并后的 content/单页文档 30 项通过。服务源码及测试、文档类型检查通过。
-
发布前测试库只读预检:两宿主 630 条早期/近期事实全部转换成功;35 位真实患者的 2,693 条当前有效事实全部转换成功。抽样不等于全库审计。
## 部署与线上验证
后端、工作台和文档站已发布。最终核验测试机 test 分支为
`5b80c04`
、工作树干净,三个容器均 running、重启计数为 0,运行镜像与构建镜像一致;后端健康检查 status=ok。来源创建时间迁移完成且未回滚,
`source_created_at`
为可空 timestamptz。发布后最近 20 分钟日志检查未发现 Invalid canonical time、open_fact_content_normalization_failed、schema-violation 或
[
drift
]
;这不代表全量历史无异常。
| 宿主 | 患者 | 当前有效事实 | 验证入口 | 单次耗时(测试机回环) |
| --- | ---: | ---: | --- | --- |
| FridaySaaS | 16 | 551 | HTTP 应用鉴权 + 查询 | 89–977 ms |
| 5i5ya | 23 | 2,310 | 同一查询服务 | 29–2,739 ms |
共 39 位患者、2,861 条事实;逐位比对数据库当前有效版本 ID 集合,全部一致。返回字段通过严格 schema,病历 11 段均为文本或 null。5i5ya 覆盖 11 类(含 5 条有效投诉),FridaySaaS 覆盖 10 类(尚未接投诉)。
关联核验:5i5ya 影像 213 条、诊断 268 条、治疗 464 条、建议 8 条保留有证据的父病历标识,未冒充接诊。FridaySaaS 48 条病历有明确接诊关联、13 条退费有来源付款关联、33 条影像诊断有影像关联。无法确认的引用保持 null。
应用鉴权使用测试服务内现有签名配置生成短期、绑定现有宿主的验收令牌,没有新建/轮换应用密钥;本轮不声称重新验证了外部 appSecret 换票。5i5ya 权限仍关闭,HTTP 正确返回 10107;内容验证不等于已开通它的外部调用权限。
## 来源时间真实原文验证
-
直接只读查询 5i5ya 数仓的 3 条真实退费,完整经过退费 project、assembler、事件生成、parser 和事实写入,sourceCreatedAt/sourceUpdatedAt 均与原文按北京时间转 UTC 的预期一致。
-
使用 PAC 留存的 3 条 FridaySaaS 病历原始事件,经过完整 manifest transforms(含同源行关联)、assembler 和事实写入,创建/更新时间与业务就诊时间分别验证;没有把录入时间冒充就诊时间。
-
写入验证使用一次性验证业务标识和同一数据库事务,核对完成后主动回滚;随后确认验证事实不存在。没有改写原事实、改源记录、触发画像召回或留下假患者。
-
验收脚本首次事务 15 秒超时,自动回滚;改用较长验收时限后通过。Friday 脚本补齐完整 transforms 和空时间断言后通过;这些是临时验收脚本修正,未修改已发布业务版本。
-
此项证明
**当前代码忠实转换原文并写入来源字段**
,不证明旧导出原文本身的时间正确,也不消除历史错误水位。旧/新原文有 8 小时表达差异的病历仍需单独甄别。
-
公网文档 HTTP 200,已核对 clinicExternalId、fileLocation、fileRefs、illnessDescription 与规范化错误说明;旧内容文档链接 308 跳转到单页 API 参考。
## 边界
-
测试库 FridaySaaS 已开通应用查询,5i5ya 未开通;不为验证扩大权限。FridaySaaS 走真实 HTTP 和应用令牌鉴权;5i5ya 直接调用相同查询服务验证内容,同时核验 HTTP 权限拒绝。
-
新代码不会自动纠正历史 8 小时时差或旧判新水位。仅重复摄入相同内容通常不会生成新版本,也不会补写 source_created_at;历史修复需要另行限定范围。
-
回退资料:测试机
`/root/pac-release-backups/20261021-open-contract-time/`
,旧镜像保留
`rollback-open-contract-20261021`
标签。新增可空列向后兼容旧服务。
docs/_archive/2026-10-meyer-and-patient-facts/2026-10-21-source-time-eight-hour-readonly-audit.md
0 → 100644
View file @
c1e09831
# 来源时间 8 小时差异:只读核查
> 历史归档(2026-10-22):本文记录当时的实现、审核或验证情况,正文中的“未提交/未部署”等状态仅指原记录日期;不代表当前版本或运行状态。现行说明见本目录索引。
核查日期:2026-10-21。范围:PAC 测试、生产的运行代码、事实/事件/同步批次、近期容器日志,以及本地 Git 历史。未修改业务代码、数据库或部署;上轮来源创建时间的本地改动保持原状。
## 结论
**主要是历史摄入的字段漏转换,当前转换逻辑已修复,但旧事实的错误时间仍存在;近期正常摄入也会遇到这些旧时间水位而被跳过。**
另外,旧病历业务时间及 Friday 旧 Mongo 导出分别有独立问题,不能把所有时间统一减 8 小时。
| 问题 | 原因与现状 | 影响 |
| --- | --- | --- |
| 多类型
`source_updated_at`
晚 8 小时 | 旧 normalizer 只转换类型登记的字段;许多类型没登记
`updatedAt`
。北京时间裸字符串被 Node UTC 进程直接解析。
`1850094`
(10/16)已补通用转换,两环境运行代码均验证正确 | 历史判新水位偏大,正常重放或较近的源修改可能被判为旧数据 |
| 5i5ya 旧病历
`occurred_at`
晚 8 小时 | 病历事件使用
`createdAt`
,早期它也漏了归一;病历 parser 又沿用事件时间。
`568a456`
(10/8)已把病历
`createdAt`
加入归一字段 | 时间轴、病历排序、末诊/医生关联、使用病历时间的召回判断可能受影响;不是只修更新水位就能解决 |
| Friday 旧病历的部分源字符串提前 8 小时 | 旧
`export.sh`
把 Mongo
`toISOString()`
的 Z 截掉,又按北京时间解释。
`fa9ba3b`
(10/15)已改为保留 Z | 与上面“漏转换”方向不同;历史病历必须按原始来源区分,不能一刀切改时间 |
当前代码修复不会自动改写旧事实。相同内容通常不会生成新版本,错误更新水位还可能让纠正后的输入先被乱序保护挡住。
## 1. 从原文到事实的实际链路
```
text
5i5ya:ClickHouse JSONEachRow → 原表行 → manifest/transforms → assembler
Friday:推送原表行/历史文件导出 → manifest/transforms → assembler
↓
normalizeCanonical(manifest: Asia/Shanghai;保留已有 Z/offset)
↓
TransactionSynthesizer(事件业务时间 + 含更新时间标记的幂等键)
↓
ParserPipeline(canonical.updatedAt → Date)
↓
FactWriter(与已有 source_updated_at 比较 → 写新版本/追加证据/stale skip)
```
-
原始时间保存在
`patient_transactions.raw_payload`
,归一后的判新时间在
`patient_facts.source_updated_at`
。
-
两环境 Node 进程均为 UTC;数据库会话时区测试为 UTC、生产为 Asia/Shanghai。字段是
`timestamptz`
,本次按真实时刻比较,不把显示时区差异当作数据偏差。
-
旧版预约已经登记
`createdAt/updatedAt`
,所以其旧样本正常;病历、接诊、诊断、治疗、影像、收退费等并未统一登记。这解释了为什么同一个宿主有的类型正确、有的类型错误。
-
5i5ya 咨询的
`updatedAt`
来自
`appointment_date`
,是判新代理时间,不是原表修改时间;它也受旧版漏转换影响;5i5ya 影像病症拆出的诊断用
`rq`
作代理判新时间,同样需要区分。投诉则使用主单及跟进聚合的快照时间,应按自己的口径比较。
### 实际例子(全部转为 UTC 比较)
| 环境/记录 | 原始值与正确解释 | 事实存值 | 结论 |
| --- | --- | --- | --- |
| 生产 Friday 旧退费 |
`updated_gmt_at=2021-07-28 14:30:05`
→
`06:30:05Z`
|
`14:30:05Z`
| 更新时间晚 8 小时;同记录退款业务时间
`14:29:49`
→
`06:29:49Z`
正确 |
| 生产 Friday 新收款 |
`updated_gmt_at=2026-10-21 18:46:13`
→
`10:46:13Z`
|
`10:46:13Z`
| 当前转换正确 |
| 生产 5i5ya 旧病历 |
`created_date=2016-05-01 12:00:32`
→
`04:00:32Z`
| 业务时间为
`12:00:32Z`
| 业务时间也晚 8 小时;该事实在 8 月写入 |
| 测试 Friday 同一病历的前后证据 | 9/28 收到创建/更新时间裸串为
`02:51:56 / 02:55:08`
,10/16 对应串变为
`10:51:56 / 10:55:08`
| 旧业务时间
`9/21 18:14Z`
,新版本
`9/22 02:14Z`
| 原文自身也存在 8 小时表达变化,不能仅根据最新原文统一修整个版本链 |
第三类的旧导出代码缺陷已由 Git 历史确认;上述前后证据都已在 PAC 核实。
**本轮未访问 Friday 源数据库或其连接器部署,不能认定每一条旧 push 都由这个导出脚本产生,也不能仅靠原文变化判断源库是否修改过记录。**
## 2. 两环境样本范围
按宿主、类型的
`occurred_at`
升/降序各取 30 个事实版本,按 ID 去重;类型包含咨询、接诊、诊断、治疗、建议、病历、影像、预约、收款、退费、投诉。测试 1,260 个版本、生产 1,220 个版本。读取关联原始事件,再追查 26 个选定主体的版本链和同步批次。
这不是随机抽样,也不是全库填充率:包括历史/现行状态,排序还可能包含空业务时间;不能从比例外推全库数量。查询均限时、只读,未跑全库聚合。
下表是
**源 updated 字段按北京时间解释后,事实水位恰好晚 8 小时的样本数**
;不包含缺值、其他差异或咨询的代理时间。
| 宿主/类型 | 测试 | 生产 |
| --- | ---: | ---: |
| 5i5ya 接诊 | 30 | 30 |
| 5i5ya 诊断 | 30 | 30 |
| 5i5ya 治疗 | 30 | 30 |
| 5i5ya 医生建议 | 0 | 28 |
| 5i5ya 病历 | 30 | 30 |
| 5i5ya 影像 | 30 | 30 |
| 5i5ya 收款 | 30 | 30 |
| Friday 咨询 | 6 | 2 |
| Friday 接诊 | 19 | 0 |
| Friday 诊断 | 2 | 0 |
| Friday 医生建议 | 24 | 15 |
| Friday 病历 | 4 | 0 |
| Friday 老影像 | 30 | 0 |
| Friday 收款 | 60 | 30 |
| Friday 退费 | 60 | 60 |
|
**合计**
|
**385**
|
**315**
|
-
这些样本中 active/fulfilled 状态分别为 344/288 个;选定主体的版本链也确认了有旧偏差仍在最新有效版本。其余是已 superseded 的历史版本,不能一起算成当前业务影响。
-
5i5ya 咨询另有测试/生产各 50 个代理时间水位晚 8 小时;没有真实 updated 字段,故未混入上表。
-
两边 5i5ya 旧病历各 30 个样本的业务时间也晚 8 小时,其中按北京时间显示跨到次日的分别有 14/12 个。生产这 30 个中 27 个 active、3 个 superseded。
-
5i5ya 预约样本两边各 60 个更新时间均正确;退费各 60 个缺失更新时间,属于上轮已修但未部署的选列遗漏,不能归类为时差。
-
今天新摄入的 5i5ya 接诊、诊断、病历、影像、收款等样本,以及生产 Friday 新接诊、病历、收款样本,更新时间均正确。旧偏差样本大多写入于 7—10 月早期,不是今天的归一函数仍普遍出错。
-
Friday 治疗等类型缺少有效 updated 值的样本不能据此判为正确;某类型本次为 0 也不代表全库无问题。
## 3. 当前跳过行为及业务影响
近期各取最多 5,000 行容器日志,测试覆盖
`12:29:01Z—13:03:10Z`
,生产覆盖
`12:28:33Z—13:12:27Z`
:
| 环境 |
`stale skip`
日志 | 其中 incoming 比 latest 早恰好 8 小时 | 类型 |
| --- | ---: | ---: | --- |
| 测试 | 4,487 | 4,487 | 咨询 3,946;诊断 541 |
| 生产 | 4,787 | 4,787 | 咨询 3,832;诊断 955 |
这是有限日志窗口内的
**跳过次数**
,不是唯一患者/事实数量,更不是丢失业务变更条数。窗口里没有
`fact write failed`
或
`bulk write failed`
,而
`stale skip`
是业务保护分支,不会等同写入异常。
进一步按日志反查了测试/生产各 4 个主体(各 2 个咨询、2 个诊断):
-
新旧事件都能关联到同一宿主、患者与业务主体;旧事实仍保存较晚的水位,新事件按当前正确时间进入后未追加到该事实的证据列表。
-
这 8 个主体的前后事件各自
`payload_hash`
相同,原文未变化。结合确切
`incoming < latest`
日志,证明存在历史水位造成的重放跳过;
**这些样例本身不是新业务内容丢失的证据**
。
-
生产咨询示例:来源日期
`2025-04-07`
,旧水位
`2025-04-07T00:00:00Z`
;当前正确输入为
`2025-04-06T16:00:00Z`
,被判为更旧。这里水位来自预约日期代理,不能解释成咨询记录真实修改时刻。
-
日志诊断样例的来源字段是
`rq`
,需按影像病症分析日的代理口径理解,不能当作原表 updated 字段。因此它们不应混入上表“原始 updated 字段”的统计。
影响需分开解释:
1.
**更新时间水位**
:本身不直接参与画像召回计算,但会决定后续事实是否可写入。相同源版本按正确时区重放会比旧错误水位早 8 小时;真正源修改发生在原修改时间之后不足 8 小时,也可能被挡住。若源更新时间已经超过该旧水位,正常新更新仍可写入,并非所有未来更新都被阻塞。
2.
**业务发生时间**
:直接被时间轴、开放事实接口、末诊/医生关联,以及召回的就诊冷却条件使用。旧病历发生时间错误可能改变排序或跨日、边界判断;本轮未计算受影响患者的画像/召回结果,不能把时间偏差数等同误召数量。
3.
**源时间原文变化**
:Friday 旧 Mongo 路线既有 UTC 标记丢失,又叠加 PAC 更新时间漏转换,部分数值可能偶然抵消。对它们套同一减 8 小时脚本会制造新的错误。
4.
**幂等与可观测性**
:事件幂等键包含更新时间文本;归一后带 offset 的文本可能形成新的事件键。但新事件已经留账,不代表事实必然更新,仍要检查写入结果。当前
`factsStaleSkipped`
在管道内计数,常规批次汇总未单独保留这个细分指标,需结合日志判断。
## 4. 后续处理边界(本轮不执行)
-
对水位问题,先按宿主、患者、来源组织、业务主体和版本绑定证据验证;仅将能证明是旧解析结果的水位列为候选,不把代理值、聚合时间、未知/冲突证据混改。仓库已有定向修复工具,但本轮未运行它,包括未跑其 dry-run。
-
对旧病历业务时间,单独评估事实版本、画像及召回依赖;不能夹在更新水位修复中顺便改。
-
对 Friday 旧 Mongo 数据,需要保留来源路径、原始表达和前后版本,必要时对照源系统的真实 UTC 瞬间,不能再用营业时间分布推断时区。
-
当前代码已经修复的路径无需重复改同一转换逻辑。先界定历史纠正范围与验证方式,再决定如何执行。
证据位置:
`field-mapper.ts`
通用时间归一、
`canonical.ts`
各资源时间元数据、
`transaction-synthesizer.ts`
事件键/时间、
`parser-pipeline.service.ts`
更新时间解析、
`fact-writer.service.ts`
单条/批量乱序闸;
`emr.parser.ts`
、
`persona.service.ts`
、
`plan-engine.service.ts`
、
`treatment-initiation-recall.scenario.ts`
、
`lookup-fact.ts`
的业务时间消费。运行状态重新核实:测试仓库
`d383418`
、服务启动 10/21;生产仓库
`d3f517b`
、服务启动 10/18。结论同时核对了运行容器的实际 normalizer,未只凭仓库 HEAD 判断。
## 5. 代码约束补齐(2026-10-21 后续本地修改,未部署)
上文保留只读核查结果。本节记录用户随后授权的代码修复,不表示线上历史数据已纠正。
已有统一入口,但原先有两个缺口:逐资源的时间清单可能漏字段;下游 datetime 契约只是非空字符串,JavaScript 又能按进程时区解析裸串。只核对宿主配置和部分正常样本不足以证明整条链路正确。
-
保留已经修复的通用 createdAt/updatedAt 归一与 Mongo 导出 UTC 标记;不重复改转换方向。
-
canonical 时间契约改为有效、带时区的 ISO 时刻;透传的 createdAt/updatedAt 也校验。源值为字符串 null 时按缺失处理,必填业务时刻仍不能为空。
-
合成流水及解析来源更新时间共用严格读取函数。绕过入口的裸时间/非法时间不再按进程时区猜测,也不静默降为无更新时间。流水合成拒收单条;解析器批量路径记录失败,不写入该条事实。
-
未支持的宿主时区明确报错,不再默认 UTC。当前宿主仍为 Asia/Shanghai;纯日期字段保持原契约。
-
从各资源 schema 自动检查全部 datetime 字段是否列入归一,同时检查全部 Friday/5i5ya assembler 的事件时间与来源创建时间配置。本次由检查发现并补齐
`image.analysis.analyzedAt`
的嵌套归一;原先该字段已有严格校验,裸串会被拒绝,不能称为已证实的时差存量。
-
不改历史事实、事件原文、乱序比较规则,不自动接受较旧版本。旧错误水位造成的跳过仍需另行处理。
本地验证:UTC 下 472 项相关回归通过;北京时间进程下 188 项核心时间回归通过;独立临时 PostgreSQL 中 12 项落库/影像链路测试通过,临时库已删除;服务及测试类型检查通过。回归覆盖保留源原文、显式时区不重复转换、纯日期边界、非法时间拒收、单条/批量写入和来源时间留空。未提交、未部署,未改主目录或现有服务。
docs/_archive/2026-10-meyer-and-patient-facts/README.md
0 → 100644
View file @
c1e09831
# 美亚与患者事实接口:开发历史归档
归档日期:2026-10-22。来源:
`meyer-imaging-adapter`
、
`open-patient-facts`
两个旧工作区。重复文档只保留一份。
## 现行入口
-
[
美亚采集器运行说明
](
../../../apps/pac-service/src/integrations/meyer/README.md
)
-
[
患者事实查询 API
](
../../../apps/pac-docs/content/docs/api/open/PatientFactsLookupController_lookup.mdx
)
-
代码收尾版本:main
`964fdd2`
、test
`2b926b1`
(归档前);两分支的已提交文件内容一致。
-
收尾验证:真实文件及目录同步测试 36 项、接口回归 289 项、权限回归 40 项通过;PAC、FridayAI 后端类型检查通过。
## 保留记录
| 文档 | 留存价值 |
| --- | --- |
|
[
2026-10-17-meyer-imaging-adapter-local.md
](
2026-10-17-meyer-imaging-adapter-local.md
)
| 初期适配器实现、联调、断点恢复及部署准备记录 |
|
[
2026-10-19-meyer-diagnosis-mapping.md
](
2026-10-19-meyer-diagnosis-mapping.md
)
| 影像所见到 PAC 诊断码的映射依据与边界 |
|
[
2026-10-19-meyer-open-facts-local.md
](
2026-10-19-meyer-open-facts-local.md
)
| 适配器与开放查询整合、真实 PostgreSQL 验收记录 |
|
[
2026-10-19-open-patient-facts-test.md
](
2026-10-19-open-patient-facts-test.md
)
| 首轮测试环境发布、回退位置与联调记录 |
|
[
2026-10-20-fact-content-field-contract-review.md
](
2026-10-20-fact-content-field-contract-review.md
)
| 17 类患者事实字段、命名、关联、时间和金额的审核过程 |
|
[
2026-10-20-meyer-open-facts-test.md
](
2026-10-20-meyer-open-facts-test.md
)
| 影像分析与开放接口精简的测试环境验收 |
|
[
2026-10-21-open-content-source-time-test.md
](
2026-10-21-open-content-source-time-test.md
)
| 字段标准及源创建时间修复的测试环境验收 |
|
[
2026-10-21-source-time-eight-hour-readonly-audit.md
](
2026-10-21-source-time-eight-hour-readonly-audit.md
)
| 历史 8 小时差异的只读核查、影响与待评估边界 |
## 阅读边界
这些是开发过程与历史验收记录,不作为现行产品承诺。早期单张分析、分页上限、诊所配置、重试策略等描述已被后续实现替代;以现行代码和上面的正式接口入口为准。日期、部署状态、样本数量及备份路径均保留当时证据,不表示本轮重新核验了服务器。
历史时间水位修正、补推与回填建议继续保留为待评估事项,本次没有执行数据修复。诊断映射中的业务口径不等于临床确诊,现行映射实现已经纳入 main。
## 工作区清理核对
-
美亚旧工作区:23 个代码/配置/测试文件全部在 main 有对应实现;19 个文件与 main 当前内容或历史版本完全一致。其余 mapper、README、两份测试仅缺少 main 历史版本后续增加的分析快照与验收覆盖,没有发现旧工作区独有的实现。
-
患者事实接口旧工作区:没有未提交代码,只有上述 8 份文档;其中两份与美亚旧工作区的副本逐字一致。
-
两个工作区的提交均已进入 main 和 test。33 个未提交文件的原始内容及修改补丁另存可恢复备份,归档文档已重写相对链接并标明历史状态。
-
忽略项仅有依赖、编译产物和文档站生成缓存,不含额外运行凭据或采集状态。
恢复备份:
`/Users/luoqi/.codex/worktree-backups/pac-meyer-closeout-20261022/`
。目录中的
`manifest.json`
记录每个原文件和备份包的 SHA-256;两个
`.tar.gz`
保留原始未提交文件,
`*-tracked.patch`
保留已跟踪文件修改。
清理结果:两处旧工作区及对应本地分支已删除,远端
`codex/open-patient-facts`
已删除(另一分支原本无远端)。现仅保留主工作区与 main、test 两条分支;主目录原有未提交文件未变。归档文档纳入 main,并同步到 test;本次仅提交文档,不部署。
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment