Commit b9a3b8b2 by luoqi

Merge completed Meyer integration and patient fact fixes into test

parents 5b80c042 7cf6a1e1
Pipeline #3856 failed in 0 seconds
This source diff could not be displayed because it is too large. You can view the blob instead.
import { z } from 'zod'; import { z } from 'zod';
import { ImageFileRefsSchema } from '@pac/types';
// 新接口专属白名单;不复用入库 passthrough,内部增加字段不会自动扩大公开契约。 // 新接口专属白名单;不复用入库 passthrough,内部增加字段不会自动扩大公开契约。
const s = z.string().nullable().optional(); const s = z.string().nullable().optional();
...@@ -148,22 +149,9 @@ export const LookupContentSchemas = { ...@@ -148,22 +149,9 @@ export const LookupContentSchemas = {
finding: s, finding: s,
capturedAt: s, capturedAt: s,
fileLocation: s, fileLocation: s,
fileRefs: ImageFileRefsSchema.nullable().optional(),
fileName: s, fileName: s,
fileType: s, fileType: s,
fileRefs: z
.array(
z
.object({
provider: z.string().min(1),
connectionId: s,
fileId: z.string().min(1),
role: z.enum(['original', 'thumbnail', 'slice']),
index: z.number().int().nonnegative().optional(),
})
.strict(),
)
.nullable()
.optional(),
analysis: LookupAnalysisSchema.nullable(), analysis: LookupAnalysisSchema.nullable(),
}) })
.strict(), .strict(),
......
...@@ -34,7 +34,7 @@ describe('shared image file references', () => { ...@@ -34,7 +34,7 @@ describe('shared image file references', () => {
expect(() => projectMeyerImageFiles({ ...old, raw: { ...old.raw, image: { ...old.raw.image, patientId: 'other' } } }, old.image)).toThrow('ownership'); expect(() => projectMeyerImageFiles({ ...old, raw: { ...old.raw, image: { ...old.raw.image, patientId: 'other' } } }, old.image)).toThrow('ownership');
expect(() => projectMeyerImageFiles(old, { ...old.image, fileRefs: [{ provider: 'meyer', fileId: 'foreign', role: 'original' }] })).toThrow('differ'); expect(() => projectMeyerImageFiles(old, { ...old.image, fileRefs: [{ provider: 'meyer', fileId: 'foreign', role: 'original' }] })).toThrow('differ');
}); });
test('common canonical → parser → fact validation → lookup works for any provider; fileUrl is unchanged', () => { test('common canonical → parser → fact validation → lookup works for any provider; source file location is preserved', () => {
const refs = [{ provider: 'another-provider', fileId: '13812345678', role: 'original' as const }]; const refs = [{ provider: 'another-provider', fileId: '13812345678', role: 'original' as const }];
const image = ImageStudyCanonicalSchema.parse({ ...meyerBundle().image, fileRefs: refs, fileUrl: 'tenant/path.png' }); const image = ImageStudyCanonicalSchema.parse({ ...meyerBundle().image, fileRefs: refs, fileUrl: 'tenant/path.png' });
const fact = new ImageParser().parse({ canonicalRow: image, transaction: { const fact = new ImageParser().parse({ canonicalRow: image, transaction: {
...@@ -43,10 +43,10 @@ describe('shared image file references', () => { ...@@ -43,10 +43,10 @@ describe('shared image file references', () => {
} })[0]!; } })[0]!;
const content = validateFactContent(fact.type, fact.subjectId, fact.content); const content = validateFactContent(fact.type, fact.subjectId, fact.content);
expect(content).toMatchObject({ file_refs: refs, file_url: 'tenant/path.png' }); expect(content).toMatchObject({ file_refs: refs, file_url: 'tenant/path.png' });
const publicFact = toLookupFact({ fact_id: 'fact', host_name: 'friday', subject_id: fact.subjectId, const publicFact = toLookupFact({ fact_id: '11111111-1111-4111-8111-111111111111', host_name: 'friday', subject_id: fact.subjectId,
type: fact.type, kind: fact.kind, status: fact.status ?? 'active', clinic_id: 'clinic-a', occurred_at: new Date(image.uploadedAt), type: fact.type, kind: fact.kind, status: fact.status ?? 'active', clinic_id: 'clinic-a', occurred_at: new Date(image.uploadedAt),
planned_for: null, valid_until: null, title: null, summary: null, content }, '诊所'); planned_for: null, valid_until: null, title: null, summary: null, content }, '诊所');
expect(publicFact.content).toMatchObject({ fileRefs: refs, fileUrl: 'tenant/path.png' }); expect(publicFact.content).toMatchObject({ fileRefs: refs, fileLocation: 'tenant/path.png' });
expect(publicFact.content).not.toHaveProperty('file_refs'); expect(publicFact.content).not.toHaveProperty('file_refs');
expect(redactJson({ finding: '电话13812345678', file_refs: refs })).toMatchObject({ finding: '电话138****5678', file_refs: refs }); expect(redactJson({ finding: '电话13812345678', file_refs: refs })).toMatchObject({ finding: '电话138****5678', file_refs: refs });
expect(redactJson({ file_refs: [{ ...refs[0], secret: 'no' }] })).toEqual({}); expect(redactJson({ file_refs: [{ ...refs[0], secret: 'no' }] })).toEqual({});
......
...@@ -139,6 +139,13 @@ describe('lookup content whitelist', () => { ...@@ -139,6 +139,13 @@ describe('lookup content whitelist', () => {
run('emr_record', { clinical_signals: [{ field: 'staff_notes' }] }).content, run('emr_record', { clinical_signals: [{ field: 'staff_notes' }] }).content,
).toMatchObject({ clinicalSignals: [{ sourceField: null }] }); ).toMatchObject({ clinicalSignals: [{ sourceField: null }] });
}); });
it('preserves stable image file references under the strict public contract', () => {
const refs = [{ provider: 'meyer', connectionId: 'clinic-a', fileId: 'file-1', role: 'original' }];
const fact = run('image_record', { file_refs: refs.map(ref => ({ ...ref, internalToken: 'secret' })) });
expect(fact.content).toMatchObject({ fileRefs: refs });
expect(JSON.stringify(fact.content)).not.toContain('internalToken');
expect(LookupFactSchema.safeParse(fact).success).toBe(true);
});
it('projects image findings and complaint child events; removes arbitrary nested fields', () => { it('projects image findings and complaint child events; removes arbitrary nested fields', () => {
const image = run('image_record', { const image = run('image_record', {
analysis: { analysis: {
......
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