open-brainy/tests/integration/txlog-origin-and-reconcile.test.ts

143 lines
5.9 KiB
TypeScript
Raw Normal View History

/**
* @module tests/integration/txlog-origin-and-reconcile
* @description Two consumer-driven cures, pinned together because they share
* the origin stamp:
*
* 1. TX-LOG ORIGIN engine-originated commits stamp `origin` on their
* tx-log entry (and the commit fact's meta) so activity feeds filter on
* fact: a downstream feed showed a "double tick" because the deferred
* vector-landing commit was indistinguishable from a user save, and the
* consumer rightly refused a time-window collapse as a quiet loss. User
* writes stay UNSTAMPED (absent origin) the pre-existing reading of
* every consumer is exact.
*
* 2. THE RECONCILE DOOR `log-live-canonical-absent` refuses auto-cure by
* design (a legitimate lost-tombstone deletion is indistinguishable from
* canonical loss); `reconcileLogDivergence(id, {attest})` is the human's
* door: 'deleted' mints the missing tombstone, 'restore' folds the log's
* copy back, wrong-class calls refuse typed with nothing written.
*/
import { describe, it, expect, afterEach } from 'vitest'
import { mkdtempSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { Brainy } from '../../src/index.js'
import { NounType } from '../../src/types/graphTypes.js'
type RawBox = {
storage: {
readNounRaw(id: string): Promise<{ metadata: unknown; vector: unknown }>
writeNounRaw(id: string, r: { metadata: unknown; vector: unknown }): Promise<void>
}
}
const dirs: string[] = []
const brains: Brainy[] = []
afterEach(async () => {
for (const b of brains.splice(0)) await b.close().catch(() => {})
for (const d of dirs.splice(0)) rmSync(d, { recursive: true, force: true })
})
async function fsBrain(): Promise<Brainy> {
const dir = mkdtempSync(join(tmpdir(), 'brainy-origin-reconcile-'))
dirs.push(dir)
const brain = new Brainy({
storage: { type: 'filesystem', path: dir },
requireSubtype: false
})
await brain.init()
brains.push(brain)
return brain
}
describe('tx-log origin stamp', () => {
it('the deferred-embed landing commit is stamped system:embed-landing; the user write is not', async () => {
const brain = await fsBrain()
await brain.add({
data: 'a row whose vector lands later',
type: NounType.Document,
metadata: { k: 1 },
deferEmbedding: true
})
await brain.awaitPendingEmbeds()
await brain.flush()
const entries = await brain.transactionLog()
const system = entries.filter((e) => (e as { origin?: string }).origin === 'system:embed-landing')
const user = entries.filter((e) => !(e as { origin?: string }).origin)
expect(system.length, 'the landing commit is stamped').toBeGreaterThanOrEqual(1)
expect(user.length, 'the user add stays unstamped').toBeGreaterThanOrEqual(1)
// The feed cure in one line: filtering !origin removes the double tick.
expect(user.length).toBeLessThan(entries.length)
}, 120000)
})
describe('reconcileLogDivergence — the attested door', () => {
/** Manufacture the class: a live log record whose canonical row is gone. */
async function manufactureDivergence(brain: Brainy): Promise<string> {
const id = await brain.add({
data: 'pre-era row whose deletion the log never saw',
type: NounType.Document,
metadata: { era: 'pre-spine' }
})
await brain.flush()
// Delete canonical BEHIND the log's back (raw write, no generation) —
// exactly the shape a deferred-durability-era crash left behind.
const storage = (brain as unknown as RawBox).storage
await storage.writeNounRaw(id, { metadata: null, vector: null })
return id
}
it("attest:'deleted' mints the missing tombstone — the oracle goes green and the commit is stamped system:reconcile", async () => {
const brain = await fsBrain()
const id = await manufactureDivergence(brain)
const before = await brain.verifyLogAuthority()
expect(
before.mismatches.some((m) => m.id === id && m.reason === 'log-live-canonical-absent'),
'the manufactured divergence is oracle-visible as the refused class'
).toBe(true)
const result = await brain.reconcileLogDivergence(id, { attest: 'deleted' })
expect(result.reconciled).toBe('tombstoned')
const after = await brain.verifyLogAuthority()
expect(after.mismatches.some((m) => m.id === id), 'the id no longer diverges').toBe(false)
expect(await brain.get(id), 'canonical stays absent').toBeNull()
await brain.flush()
const entries = await brain.transactionLog()
expect(
entries.some((e) => (e as { origin?: string }).origin === 'system:reconcile'),
'the reconcile commit is origin-stamped'
).toBe(true)
}, 120000)
it("attest:'restore' folds the log's copy back into canonical", async () => {
const brain = await fsBrain()
const id = await manufactureDivergence(brain)
const result = await brain.reconcileLogDivergence(id, { attest: 'restore' })
expect(result.reconciled).toBe('restored')
const row = await brain.get(id)
expect(row, 'the logs only copy lives again').not.toBeNull()
expect((row!.metadata as { era: string }).era).toBe('pre-spine')
expect((await brain.verifyLogAuthority()).mismatches.some((m) => m.id === id)).toBe(false)
}, 120000)
it('wrong-class calls refuse typed with nothing written', async () => {
const brain = await fsBrain()
const id = await brain.add({ data: 'healthy row', type: NounType.Document, metadata: { n: 1 } })
await brain.flush()
// Canonical present + log agrees: not the class — refuse, name the state.
await expect(brain.reconcileLogDivergence(id, { attest: 'deleted' })).rejects.toThrow(
/canonical is PRESENT/
)
expect(await brain.get(id), 'nothing was written').not.toBeNull()
// Unknown id: no log record at all — refuse, name it.
await expect(
brain.reconcileLogDivergence('00000000-0000-7000-8000-00000000dead', { attest: 'restore' })
).rejects.toThrow(/no record at all/)
}, 120000)
})