/* * ★ **원본에 있는데 세우지 않은 것** — 그 사실이 스쳐 지나가지 않게. * * ── 무엇이 아무 신호도 내지 않았나 (2026-08-24) ──────────────────────────────────────────── * 커넥터가 원본의 사실 일부를 **일부러 받지 않는 일이 정상이다**(입자가 안 맞는다 · 받으면 상태가 * 거짓이 된다 · 커널 어휘로 옮길 수 없다). 그때 경고를 내는데, 그 경고의 유일한 소비처가 **프로비저닝 * 마법사**였다 — 트윈을 만드는 동안만 뜨는 화면이다. * * 그래서 「지시되지 않은 생산계획 8건을 세우지 않았다」가 **한 번 스쳐 지나갈 뿐**이었고, 나중에 * 사용자가 「원본보다 계획이 적다」를 물으면 답이 어디에도 없었다. * * 그 사실은 한 번의 사건이 아니라 **상태의 성질**이다 — 세우지 않은 것은 **지금도** 트윈에 없다. * * ── `unhandled` 의 형제다 ────────────────────────────────────────────────── * `unhandled` 리듀서가 **받았는데** 담을 자리를 몰랐다 * 여기 커넥터가 **보지만 일부러 보내지 않았다** — 이유와 함께 * * ── 그래서 문에서 조회까지 걷는다 ─────────────────────────────────────────── * 오늘 「계약에 자리는 있고 그 자리로 가는 길이 없다」를 여섯 번 만났다. 장부만 검사하면 어댑터가 * 부를 문이 없는 것을 못 잡는다 — 그것이 그 결함들이 살아남은 방식이다. */ import { test } from 'node:test' import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import { createRequire } from 'node:module' const req = createRequire(import.meta.url) const { newIngestLedger, recordWithheld, ingestHealth } = req('../dist-server/engine/ingest-health.js') const REASON = '아직 지시되지 않은 생산계획을 세우지 않았다 — 커널의 created 는 「할당해도 되는 오더」를 뜻한다' test('★ 세우지 않은 것이 조회에 나온다 — 유입이 한 건도 없어도', () => { /* * 이 갈래가 중요하다: 원본이 말하는데 **전부** 안 받는 경우가 있고, 그때 유입은 0 이다. * 유입 있는 갈래에서만 내면 바로 그 상황에서 들어온 것이 없어진다. */ const l = newIngestLedger() recordWithheld(l, REASON, 8, Date.parse('2026-08-24T11:19:16.000Z')) const view: any = ingestHealth(l) assert.equal(view.withheld?.length, 1) assert.equal(view.withheld[0].reason, REASON) assert.equal(view.withheld[0].count, 8) assert.equal(view.withheld[0].lastAt, '2026-08-24T11:19:16.000Z', '언제 그랬는지 함께 — 「지금도 그런가」를 사람이 판정한다') }) test('주기마다 불러도 부풀지 않는다 — 누적이 아니라 **지금 세우지 않은 수**다', () => { /* 8건이 매 주기 다시 보고되면 8 이어야 한다. 더해서 800 이 되면 거짓이다. */ const l = newIngestLedger() for (let i = 0; i < 100; i++) recordWithheld(l, REASON, 8, 1000 + i) assert.equal(l.withheld.length, 1) assert.equal(l.withheld[0].count, 8) assert.equal(l.withheld[0].lastAtMs, 1099, '마지막 시각으로 움직인다') }) test('수가 달라지면 마지막 수로 덮는다 — 낡은 수가 남지 않게', () => { const l = newIngestLedger() recordWithheld(l, REASON, 8, 1000) recordWithheld(l, REASON, 3, 2000) assert.equal(l.withheld[0].count, 3) }) test('이유가 여럿이면 각자 한 줄 — 다른 사실을 한 줄로 뭉치지 않는다', () => { const l = newIngestLedger() recordWithheld(l, REASON, 8, 1000) recordWithheld(l, '사람이 올린 문서라 자재와 이어지지 않는다', 46, 1000) assert.equal((ingestHealth(l) as any).withheld.length, 2) }) test('말하지 않은 것은 만들지 않는다 — 빈 목록을 「세우지 않은 것이 있다」로 읽히게 하지 않는다', () => { const l = newIngestLedger() assert.equal((ingestHealth(l) as any).withheld, undefined, '키 자체가 없다') recordWithheld(l, REASON, 0, 1000) assert.equal(l.withheld, undefined, '0 은 적지 않는다') recordWithheld(l, '', 5, 1000) assert.equal(l.withheld, undefined, '이유 없는 것은 적지 않는다') }) test('★ 어댑터가 부를 문이 있고, 그 문이 장부에 닿는다', () => { /* * 이 단정이 오늘 여섯 번 만난 부류를 막는다. 장부만 검사하면 **어댑터가 부를 통로가 없는 것**을 * 못 잡고, 그러면 보내는 쪽에는 「알렸다」로 보이고 화면에는 「없다」로 보인다. */ const adapter = readFileSync(new URL('../server/service/reference/reference-adapter.ts', import.meta.url), 'utf-8') assert.match(adapter, /onWithheld\?: \(info: \{ reason: string; count: number \}\) => void/, '계약에 통로가 있다') const live = readFileSync(new URL('../server/service/reference/reference-live.ts', import.meta.url), 'utf-8') const wired = live.slice(live.indexOf('onWithheld'), live.indexOf('onWithheld') + 260) assert.match(wired, /recordIngestWithheld/, '그 통로가 장부로 이어진다') const engine = readFileSync(new URL('../server/engine/twin-engine.ts', import.meta.url), 'utf-8') const fn = engine.slice(engine.indexOf('static recordIngestWithheld')) assert.match(fn.slice(0, 700), /recordWithheld\(ledger/, '엔진이 장부에 적는다') /* 실패로 적지 않는다 — 어댑터의 옳은 판단이고, 오류로 적으면 화면이 원본을 의심한다. */ assert.doesNotMatch(fn.slice(0, 700), /lastError|status:/, '오류로 적지 않는다') })