From e766ed0a846a251e0807eb525f29829b56c3e2b0 Mon Sep 17 00:00:00 2001 From: David Snelling Date: Wed, 2 Sep 2026 16:14:24 -0700 Subject: [PATCH] test(find-connected): close the brain this file leaks, and name the half a short answer came from MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TWO THINGS, both about the same file. THE LEAK, which is a defect of the test. `afterAll` set `brain = null`. That does not close a brain — it only makes it unreachable from here. The instance stayed open and registered with its unref'd cadence timer running, and the gate config runs the whole suite in ONE process (pool: 'forks', singleFork: true — two files report the same process.pid), so a brain leaked in this file goes on narrating its flushes into every file that runs after it. This one holds 151 entities and 30 relations. It is closed now. It is not the only leaker in the suite — a create-versus-close scan turns up 67 files with the same shape, and this is one of them, not the cause of anything on its own. Fixing the file I was already in. THE DIAGNOSTIC. 'walks the vector leg over the neighbours only' went red on the gate box (1 row of a requested 5) while passing here in isolation eight runs out of eight, beside its own box predecessor, and under a perturbed random stream — and it passed on the box one gate earlier behind the IDENTICAL predecessor. So the cause is process state accumulated by the time this file runs, and a bare count mismatch says nothing about which half broke. The case now runs the same query without the vector leg first, as a control, and reports both counts: both short means the neighbour set or the filter, only the vector leg short means the walk — which matters here because every row in this corpus carries an IDENTICAL vector, so the walk is ranking an exact tie and a tie has no defined order to return 5 of. The assertion is unchanged: still exactly 5, still every row a neighbour. --- .../integration/find-connected-order.test.ts | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/tests/integration/find-connected-order.test.ts b/tests/integration/find-connected-order.test.ts index b04e7f99..3b7560e4 100644 --- a/tests/integration/find-connected-order.test.ts +++ b/tests/integration/find-connected-order.test.ts @@ -67,6 +67,13 @@ describe('find({ connected }) is graph-first: neighbours → filter → page', ( }) afterAll(async () => { + // CLOSE IT. Dropping the reference does not close a brain — it only makes + // it unreachable from here. The instance stays open and registered, its + // unref'd cadence timer keeps running, and because the gate config runs the + // whole suite in ONE process (pool: 'forks', singleFork: true) it goes on + // narrating its flushes into every test file that runs after this one. + // A test that leaks a brain is a defect of the test. + await brain?.close() brain = null as any }) @@ -137,13 +144,34 @@ describe('find({ connected }) is graph-first: neighbours → filter → page', ( }) it('walks the vector leg over the neighbours only', async () => { + // The SAME query without the vector leg, first. Both legs draw from the + // one neighbour set, so this is the control: it says whether a short answer + // came from the adjacency/filter (both legs short) or from the vector walk + // alone (only the vector leg short). Cheap, and it turns a bare count + // mismatch into a named half — this case has gone red on the gate box + // while passing in isolation and beside its own predecessor, so the next + // red must arrive already carrying the half it belongs to. + const control = await brain.find({ + connected: { from: anchor, direction: 'out' }, + where: { kind: 'note' }, + limit: 5 + }) + const results = await brain.find({ vector: sharedVector, connected: { from: anchor, direction: 'out' }, where: { kind: 'note' }, limit: 5 }) - expect(results).toHaveLength(5) + + expect( + results.length, + `the vector leg returned ${results.length} of a requested 5. The same query ` + + `WITHOUT the vector returned ${control.length}: if that is also short the ` + + `neighbour set or the filter is the cause, and if it is 5 the vector walk is — ` + + `note every row in this corpus carries an identical vector, so the walk is ` + + `ranking an exact tie.` + ).toBe(5) for (const r of results) expect(neighbourIds.has(r.entity.id)).toBe(true) })