One deterministic v2 log (nine facts covering every fold-relevant behavior: genesis, after-images with minted ints, a deferred embed pending→landed, a sameAsGeneration vector ref, a verb, a tombstone, and an all-deduped empty commit) whose ENCODED BYTES and FOLDED STATE are both pinned by sha256 literals. The fixture (tests/fixtures/golden-log-v2.bin, 4128 B, byte-verified against the encoder on every run) is the shared artifact a second reader implementation consumes — it must reproduce the identical fold digest; the pair is normative on disagreement. The fold law is stated in prose beside the code: generation-ordered latest-per-id, tombstone masking, embed.landed vector application, single-hop ref resolution, key-sorted digest. Also: decodeGroupV2 discriminated pad filler by RECORD COUNT, silently swallowing legitimate empty commits (an all-deduped batch at a real generation). Pads carry generation 0 — which writers can never mint — so the generation is the honest discriminator; empty commits stay visible. Pins: 4/4 (encode-exact, fixture-identical, fold-exact, human-readable spot checks beside the hashes).
170 lines
7.8 KiB
TypeScript
170 lines
7.8 KiB
TypeScript
/**
|
|
* @module tests/conformance/golden-log-fold
|
|
* @description THE GOLDEN-LOG FOLD-CONFORMANCE ORACLE (brainy leg).
|
|
*
|
|
* One deterministic v2 log — fixed ids, ints, timestamps, vectors — whose
|
|
* ENCODED BYTES and whose FOLDED STATE are both pinned by content hash.
|
|
* The second (native) reader implementation consumes the identical fixture
|
|
* (tests/fixtures/golden-log-v2.bin, written and verified here) and must
|
|
* produce the identical fold digest; the pair is normative on disagreement.
|
|
*
|
|
* What the pins catch, loudly:
|
|
* - Any byte drift in the encoder (envelope, msgpack layout, seals, CRC).
|
|
* - Any semantic drift in the fold (tombstone masking, vector landing,
|
|
* sameAsGeneration resolution, last-writer-wins ordering).
|
|
* - Any divergence between the two implementations, before the cut.
|
|
*
|
|
* The pinned hashes change ONLY with a deliberate, versioned format or
|
|
* fold-law change — never silently. Updating them requires updating the
|
|
* fixture AND the native side in the same train.
|
|
*/
|
|
import { describe, it, expect } from 'vitest'
|
|
import { createHash } from 'node:crypto'
|
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs'
|
|
import { join, dirname } from 'node:path'
|
|
import {
|
|
encodeFactV2,
|
|
encodeSegmentHeaderV2,
|
|
sealGroup,
|
|
decodeGroupV2,
|
|
SEGMENT_HEADER_BYTES,
|
|
type CommitFactV2,
|
|
type LogRecord
|
|
} from '../../src/db/factLogFormat.js'
|
|
import { recordDigest } from '../../src/db/logAuthority.js'
|
|
|
|
const FIXTURE = join(__dirname, '../fixtures/golden-log-v2.bin')
|
|
|
|
const sha256 = (b: Uint8Array): string => createHash('sha256').update(b).digest('hex')
|
|
|
|
// Fixed identities — never regenerate.
|
|
const BRAIN = '00000000-0000-4000-8000-00000000b1a1'
|
|
const A = '00000000-0000-4000-8000-0000000000a1'
|
|
const B = '00000000-0000-4000-8000-0000000000b2'
|
|
const C = '00000000-0000-4000-8000-0000000000c3'
|
|
const V = '00000000-0000-4000-8000-0000000000d4'
|
|
|
|
const vec = (seed: number): number[] => [seed + 0.25, seed + 0.5, seed + 0.75]
|
|
|
|
/** The golden fact sequence — every fold-relevant behavior in nine facts. */
|
|
function goldenFacts(): CommitFactV2[] {
|
|
const f = (generation: number, records: LogRecord[]): CommitFactV2 => ({
|
|
generation,
|
|
timestamp: 1_700_000_000_000 + generation,
|
|
records
|
|
})
|
|
return [
|
|
f(1, [{ type: 'log.genesis', idSpaceWidth: 64, brainId: BRAIN, createdAt: 1_700_000_000_000 }]),
|
|
f(2, [{ type: 'noun.afterImage', id: A, entityInt: 1n, metadata: { name: 'alpha', rank: 1 }, vectorLeg: vec(1) }]),
|
|
f(3, [
|
|
{ type: 'noun.afterImage', id: B, entityInt: 2n, metadata: { name: 'beta' }, vectorLeg: null },
|
|
{ type: 'embed.pending', id: B, enqueuedAt: 1_700_000_000_003 }
|
|
]),
|
|
// A metadata-only update: the vector rides by reference to generation 2.
|
|
f(4, [{ type: 'noun.afterImage', id: A, entityInt: 1n, metadata: { name: 'alpha', rank: 2 }, vectorLeg: { sameAsGeneration: 2 } }]),
|
|
// B's deferred vector lands.
|
|
f(5, [{ type: 'embed.landed', id: B, vector: vec(9) }]),
|
|
// A relationship.
|
|
f(6, [{ type: 'verb.afterImage', id: V, verbInt: 3n, metadata: { w: 0.5 }, vectorLeg: null, verb: 'relatedTo', sourceId: A, sourceInt: 1n, targetId: B, targetInt: 2n }]),
|
|
// C exists briefly…
|
|
f(7, [{ type: 'noun.afterImage', id: C, entityInt: 4n, metadata: { name: 'gamma' }, vectorLeg: vec(7) }]),
|
|
// …and is tombstoned (masking must hold in the fold).
|
|
f(8, [{ type: 'noun.tombstone', id: C }]),
|
|
// An all-deduped batch: a real generation with zero records.
|
|
f(9, [])
|
|
]
|
|
}
|
|
|
|
/** Build the golden segment: v2 header + sealed frame group. */
|
|
function goldenSegment(): Uint8Array {
|
|
// Single-hop law: generation 2 carried A's inline vector (5 carries B's
|
|
// via embed.landed); the ref in generation 4 must verify against it.
|
|
const inline = new Set([2, 5, 7])
|
|
const frames = goldenFacts().map((fact) => encodeFactV2(fact, { inlineVectorGenerations: inline }))
|
|
const sealed = sealGroup(frames, 4096)
|
|
const out = new Uint8Array(SEGMENT_HEADER_BYTES + sealed.length)
|
|
out.set(encodeSegmentHeaderV2(1, 4096), 0)
|
|
out.set(sealed, SEGMENT_HEADER_BYTES)
|
|
return out
|
|
}
|
|
|
|
/**
|
|
* THE FOLD LAW (shared with the native implementation, normative):
|
|
* fold facts in generation order → per-id latest state with tombstone
|
|
* masking; embed.landed applies the vector to the id's current state;
|
|
* {sameAsGeneration: N} resolves to the inline vector the log carried at N;
|
|
* verbs fold like nouns under their own ids. Digest = recordDigest (key-
|
|
* sorted JSON sha256) of the id-sorted state map.
|
|
*/
|
|
function foldGoldenLog(bytes: Uint8Array): string {
|
|
const group = decodeGroupV2(bytes.slice(SEGMENT_HEADER_BYTES))
|
|
const state = new Map<string, Record<string, unknown>>()
|
|
const inlineVectorAt = new Map<number, number[]>()
|
|
for (const fact of group.facts) {
|
|
for (const rec of fact.records) {
|
|
if (rec.type === 'noun.afterImage' || rec.type === 'verb.afterImage') {
|
|
let vector: number[] | null = null
|
|
if (Array.isArray(rec.vectorLeg)) {
|
|
vector = rec.vectorLeg
|
|
inlineVectorAt.set(fact.generation, vector)
|
|
} else if (rec.vectorLeg && typeof rec.vectorLeg === 'object' && 'sameAsGeneration' in rec.vectorLeg) {
|
|
vector = inlineVectorAt.get((rec.vectorLeg as { sameAsGeneration: number }).sameAsGeneration) ?? null
|
|
}
|
|
state.set(rec.id, {
|
|
kind: rec.type === 'noun.afterImage' ? 'noun' : 'verb',
|
|
int: (rec.type === 'noun.afterImage'
|
|
? (rec as { entityInt: bigint }).entityInt
|
|
: (rec as { verbInt: bigint }).verbInt
|
|
).toString(),
|
|
metadata: rec.metadata,
|
|
vector,
|
|
generation: fact.generation
|
|
})
|
|
} else if (rec.type === 'noun.tombstone' || rec.type === 'verb.tombstone') {
|
|
state.delete(rec.id)
|
|
} else if (rec.type === 'embed.landed') {
|
|
const cur = state.get(rec.id)
|
|
if (cur) state.set(rec.id, { ...cur, vector: rec.vector, generation: fact.generation })
|
|
inlineVectorAt.set(fact.generation, rec.vector)
|
|
}
|
|
// embed.pending / genesis / blob / projection notes carry no fold state here.
|
|
}
|
|
}
|
|
const sorted = [...state.entries()].sort(([x], [y]) => (x < y ? -1 : 1))
|
|
return recordDigest(sorted)
|
|
}
|
|
|
|
// ── THE PINS ────────────────────────────────────────────────────────────────
|
|
// Byte-exact encode + semantics-exact fold. These literals are the contract.
|
|
const GOLDEN_BYTES_SHA256 = 'f898ed29f6f7d41135c6c85eb07725348b20cf8efec5f050ff50ad6d54a09dad'
|
|
const GOLDEN_FOLD_DIGEST = 'fad1b1d9865d6c9c84493c5481599ebd39b7ecf4cd203af4c435dfea7cd78ed4'
|
|
|
|
describe('golden-log fold conformance (brainy leg)', () => {
|
|
it('the encoder reproduces the golden bytes exactly', () => {
|
|
const seg = goldenSegment()
|
|
expect(seg.length % 4096, 'sealed to the sector boundary (header excluded)').toBe(SEGMENT_HEADER_BYTES % 4096)
|
|
expect(sha256(seg)).toBe(GOLDEN_BYTES_SHA256)
|
|
})
|
|
|
|
it('the fixture on disk is byte-identical (the shared artifact both readers consume)', () => {
|
|
const seg = goldenSegment()
|
|
if (!existsSync(FIXTURE)) {
|
|
mkdirSync(dirname(FIXTURE), { recursive: true })
|
|
writeFileSync(FIXTURE, seg)
|
|
}
|
|
const onDisk = new Uint8Array(readFileSync(FIXTURE))
|
|
expect(sha256(onDisk), 'fixture bytes match the encoder').toBe(GOLDEN_BYTES_SHA256)
|
|
})
|
|
|
|
it('folding the golden log yields the pinned state digest', () => {
|
|
expect(foldGoldenLog(goldenSegment())).toBe(GOLDEN_FOLD_DIGEST)
|
|
})
|
|
|
|
it('fold semantics spot-checks (human-readable guardrails beside the hash)', () => {
|
|
const group = decodeGroupV2(goldenSegment().slice(SEGMENT_HEADER_BYTES))
|
|
expect(group.facts.length, 'nine facts, pads invisible').toBe(9)
|
|
const gens = group.facts.map((f) => f.generation)
|
|
expect(gens).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9])
|
|
expect(group.facts[8].records).toEqual([])
|
|
})
|
|
})
|