/* * A refusal has to name which envelope was refused. * * ── What this catches, and why the existing test did not (2026-09-08) ────── * `rejectedForCaller` pairs a refused record with its envelope by **object identity** — value * comparison would let two identically shaped records take each other's id. Its own test * hands the same object to both sides, so it passes and proves the pairing works. * * It does not prove anything about the real path, because in between * `ingestCanonicalRecords` builds `{ ...r, eventTime, sourceType }` — **a new object**. The * refusal then carries that copy, the copy is not in the identity map, and the response comes * back as `{ record, errors }` with no `eventId`: * * sent {"eventId":"probe-eventid-check-001","record":{"kind":"transformation"}} * back rejected: [{ record: {kind:"transformation", sourceType:"twin"}, errors:[…] }] * * The sending side cannot mark the row that was refused, so it cannot settle the batch and * its queue stops moving — measured on the plant side as 719 envelopes pending with nothing * lost and nothing advancing. * * So this test walks the seam the way a real envelope does: through the ingest that makes the * copy, then through the pairing. That is the step a pure test of either half cannot take. */ import { test } from 'node:test' import assert from 'node:assert/strict' import { ingestCanonicalRecords } from '../server/engine/canonical-ingest.js' import { rejectedForCaller } from '../server/service/reference/hook-rejected.js' const AT = '2026-09-08T02:00:00.000Z' /** A transformation the kernel refuses — no inputs, no outputs, no bizStep. */ const REFUSED = { kind: 'transformation' } as any test('a refusal names the envelope it came from, after ingest has copied the record', () => { /* The envelope as the hook holds it: the record object, and the id that identifies its row. */ const items = [{ record: REFUSED, eventId: 'evt-refused-1' }] const result = ingestCanonicalRecords( items.map(i => i.record), 'test-domain', AT ) as any assert.equal(result.rejected.length, 1, 'the kernel refuses this record') const forCaller = rejectedForCaller(result.rejected, items) assert.deepEqual( forCaller.map((r: any) => r.eventId), ['evt-refused-1'], 'the refusal carries the envelope id — without it the sender cannot mark the row' ) }) test('two refused records of the same shape keep their own ids', () => { /* * This is why the pairing is by identity and not by value. Both records look the same, and * value comparison would hand the first id to both — the sender would mark one row twice * and leave the other pending forever. */ const a = { kind: 'transformation' } as any const b = { kind: 'transformation' } as any const items = [ { record: a, eventId: 'evt-a' }, { record: b, eventId: 'evt-b' } ] const result = ingestCanonicalRecords( items.map(i => i.record), 'test-domain', AT ) as any const forCaller = rejectedForCaller(result.rejected, items) assert.deepEqual( forCaller.map((r: any) => r.eventId).sort(), ['evt-a', 'evt-b'], 'each refusal keeps its own id' ) }) test('an envelope with no id still says what was refused', () => { /* * A connector that does not number its envelopes gets the record back instead. An empty id * would be worse than none: the sender would look for a row, find nothing, and treat the * batch as understood. */ const items = [{ record: REFUSED }] const result = ingestCanonicalRecords( items.map(i => i.record), 'test-domain', AT ) as any const forCaller = rejectedForCaller(result.rejected, items) as any[] assert.equal(forCaller.length, 1) assert.equal('eventId' in forCaller[0], false, 'no id is sent rather than an empty one') assert.ok('record' in forCaller[0], 'the record is sent so a person can see what was dropped') })