/* * 같은 사실을 두 번 받았을 때 한 번으로 세는 근거 — **정체**. * * 정체를 못 만들면 그 사실은 dedupe 밖이고, 다시 받을 때마다 저널에 새로 앉는다. backfill 이 그것을 * 드러냈다(2026-09-06). */ import { test } from 'node:test' import assert from 'node:assert/strict' import { factIdentity, takeUnidentified } from '../server/engine/ingest-dedupe.js' /* ── 주체가 subjectId 인 사실 ───────────────────────────────────────────────── */ test('★ 처분과 시험은 subjectId 가 주체다 — 그 이름이 없으면 정체가 안 만들어진다', () => { /* * [측정함 2026-09-06] `fillTwinScope` 를 돌릴 때마다 처분 4건 · 시험 3건이 다시 앉았다. 나머지 * 34건은 걸러지는데 이 둘만 계속 늘었다. * * 원인은 `discriminatorsOf` 에 `subjectId` 가 없어서 `parts` 가 비고, `factIdentity` 가 * `undefined` 를 낸 것이다. 정체가 없으면 dedupe 밖이다. */ const disposition = { eventType: 'nonconformance.disposition', eventTime: '2026-09-01T02:50:51.832Z', data: { subjectId: 'LOT-A', decision: 'scrap', quantity: 50 } } const id = factIdentity(disposition) assert.ok(id, '정체를 못 만들면 다시 받을 때마다 새로 앉는다') assert.ok(id!.includes('subject=LOT-A'), `주체가 정체에 안 들어갔다: ${id}`) }) test('★ 다른 로트의 같은 처분은 다른 사실이다', () => { const at = '2026-09-01T02:50:51.832Z' const a = factIdentity({ eventType: 'nonconformance.disposition', eventTime: at, data: { subjectId: 'LOT-A', decision: 'scrap' } }) const b = factIdentity({ eventType: 'nonconformance.disposition', eventTime: at, data: { subjectId: 'LOT-F', decision: 'scrap' } }) assert.notEqual(a, b, '두 로트의 처분이 한 사실로 뭉쳤다') }) test('★ 같은 사실을 다시 받으면 같은 정체다 — backfill 이 저널을 안 부풀린다', () => { const rec = { eventType: 'nonconformance.disposition', eventTime: '2026-09-01T02:50:51.832Z', data: { subjectId: 'LOT-A', decision: 'scrap', quantity: 50 } } assert.equal(factIdentity(rec), factIdentity({ ...rec, data: { ...rec.data } })) }) test('★ 시험 결과는 명세도 가른다 — 같은 대상에 시험이 여럿이다', () => { const at = '2026-09-01T00:00:00.000Z' const a = factIdentity({ eventType: 'test.result', eventTime: at, data: { subjectId: 'EQ-1', specId: 'CP-PBA-INCOMING' } }) const b = factIdentity({ eventType: 'test.result', eventTime: at, data: { subjectId: 'EQ-1', specId: 'CP-PBA-TEST' } }) assert.notEqual(a, b, '같은 대상의 두 시험이 한 사실로 뭉쳤다') }) test('★ 정체를 못 만든 것을 센다 — 조용히 dedupe 밖으로 나가지 않는다', () => { takeUnidentified() assert.equal(factIdentity({ eventType: 'made.up.kind', eventTime: '2026-09-01T00:00:00.000Z', data: {} }), undefined) assert.deepEqual(takeUnidentified(), { 'made.up.kind': 1 }) assert.deepEqual(takeUnidentified(), {}, '읽고 비운다') })