Compare commits

..

No commits in common. "v10.3.1" and "v10.3.0" have entirely different histories.

8 changed files with 36 additions and 251 deletions

View file

@ -2,12 +2,6 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [10.3.1](https://source.soulcraft.com/soulcraft/brainy/compare/v10.3.0...v10.3.1) (2026-08-18)
- docs(releases): the 10.3.1 consumer entry — the fold that behaves (900cc895)
- fix(recovery): the fold streams and narrates; the checkpoint chain arms at the flip (ed7d1db9)
### [10.3.0](https://source.soulcraft.com/soulcraft/brainy/compare/v10.2.0...v10.3.0) (2026-08-18)
- docs(releases): the 10.3.0 consumer entry — the trust-and-provenance release (97d75649)

View file

@ -31,33 +31,6 @@ is sometimes cited as a 7.x removal — those methods never existed on 7.x; the
---
## v10.3.1 — 2026-08-18 (the fold that behaves)
Three recovery cures from one production first-boot incident (a brain's first
process restart after a live storage-authority flip looked hung and was
restarted three times mid-recovery). **Adopt this version before flipping
brains with existing history** — it is the intended adoption target for
fleets moving to the crash-safe authority.
- **Recovery streams.** The boot-time log fold now consumes the generation
log one segment-batch at a time — memory stays bounded at one segment for
any log size. Previously it materialized every fact into one array, which
on a ~7k-fact log produced multi-GB allocation pressure and a process that
looked wedged while it worked.
- **Recovery narrates.** The fold announces itself before the work begins
("recovery fold beginning — do not restart, the fold is finite") and prints
progress every thousand facts. A visible fold gets to finish; a silent one
gets killed by a well-meaning operator, and each kill makes the next boot
pay the whole fold again.
- **Bounded recovery from the flip itself.** Adopting the log authority now
founds the recovery checkpoint at the moment of the flip (one paged
canonical sync, bounded memory, then the stamp) — so even the FIRST unclean
shutdown after a flip replays only the log's tail. Previously the bound
could only establish itself at a completed crash recovery, which is exactly
the recovery the incident kept interrupting.
---
## v10.3.0 — 2026-08-18 (the trust-and-provenance release)
Four consumer-driven cures. Pairs with the same native accelerator line

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "@soulcraft/brainy",
"version": "10.3.1",
"version": "10.3.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@soulcraft/brainy",
"version": "10.3.1",
"version": "10.3.0",
"license": "MIT",
"dependencies": {
"@msgpack/msgpack": "^3.1.2",

View file

@ -1,6 +1,6 @@
{
"name": "@soulcraft/brainy",
"version": "10.3.1",
"version": "10.3.0",
"description": "Universal Knowledge Protocol™ - World's first Triple Intelligence database unifying vector, graph, and document search in one API. Stage 3 CANONICAL: 42 nouns × 127 verbs covering 96-97% of all human knowledge.",
"main": "dist/index.js",
"module": "dist/index.js",

View file

@ -8392,57 +8392,6 @@ export class Brainy<T = any> implements BrainyInterface<T> {
// Fold-checkpoint chain, phase 2: the flip is recorded — open the stamp
// gate so the next flush/close barrier writes the first checkpoint.
this.generationStore.completeFoldCheckpointBootstrap()
// ARM-AT-FLIP for the NON-FRESH brain (the chain refused the fresh-brain
// arm because committed > 0): run one paged FULL canonical barrier now —
// every live row's canonical bytes fsynced, bounded memory — then stamp
// the first checkpoint. Without this, the chain could only arm at the
// brain's first crash, and that crash paid a WHOLE-LOG fold: a production
// brain hit exactly that on its first post-flip boot (a full-log
// materializing fold, restarted three times mid-flight). Adoption already
// pays O(N) oracle work; one more O(N) barrier founds bounded recovery
// from minute zero.
if (!this.generationStore.foldCheckpointChainArmed()) {
const PAGE = 500
let synced = 0
prodLog.info(
`[Brainy] adoptLogAuthority: founding the fold checkpoint — syncing every ` +
`row's canonical bytes (paged; progress every 2000 rows)`
)
let offset = 0
let cursor: string | undefined
for (;;) {
const page = await this.storage.getNouns({
pagination: cursor ? { limit: PAGE, cursor } : { limit: PAGE, offset }
})
const ids = page.items.map((i) => (i as { id: string }).id)
if (ids.length > 0) {
await this.storage.syncEntityCanonical?.(ids, [])
synced += ids.length
if (synced % 2000 < PAGE && synced >= 2000) {
prodLog.info(`[Brainy] adoptLogAuthority: checkpoint founding — ${synced} rows synced`)
}
}
if (page.hasMore && page.nextCursor) { cursor = page.nextCursor; offset += ids.length; continue }
if (page.hasMore && !page.nextCursor) { offset += PAGE; continue }
break
}
let vOffset = 0
let vCursor: string | undefined
for (;;) {
const page = await this.storage.getVerbs({
pagination: vCursor ? { limit: PAGE, cursor: vCursor } : { limit: PAGE, offset: vOffset }
})
const ids = page.items.map((i) => (i as { id: string }).id)
if (ids.length > 0) {
await this.storage.syncEntityCanonical?.([], ids)
synced += ids.length
}
if (page.hasMore && page.nextCursor) { vCursor = page.nextCursor; vOffset += ids.length; continue }
if (page.hasMore && !page.nextCursor) { vOffset += PAGE; continue }
break
}
await this.generationStore.stampFoldCheckpointAfterFullBarrier()
}
return report
}

View file

@ -770,43 +770,6 @@ export class FactLog {
* segments directly; the torn tail's invalid suffix is ignored exactly
* like open() would).
*/
/**
* STREAMING twin of {@link FactLog.peekFactsAbove} for the recovery fold:
* yields facts above the bound one SEGMENT at a time, ascending, without
* ever materializing the whole log (a production first-boot fold OOM-class
* allocation storm came from exactly that GBs of decoded after-images in
* one array while the process looked hung). Memory is one segment's worth.
* Works manifest-direct (safe before {@link FactLog.open}). Ordering is
* structural (segments rotate in order; appends are ordered within one) and
* ASSERTED a violation aborts loudly, never a silent misordered replay.
*/
async *streamFactsAbove(committedGeneration: number): AsyncGenerator<CommitFact[], void> {
const stored = (await this.storage.readRawObject(FACTS_MANIFEST_PATH)) as FactsManifest | null
if (!stored || typeof stored !== 'object' || !Array.isArray(stored.segments)) return
if (stored.formatVersion !== FACTS_FORMAT_VERSION) return
const files = [...stored.segments.map((s) => s.file)]
if (stored.tailSegment) files.push(stored.tailSegment)
let lastGen = committedGeneration
for (const file of files) {
const bytes = await this.storage.readRawBytes(`${FACTS_PREFIX}/${file}`)
if (bytes === null) continue
const { facts } = parseSegment(file, bytes)
const batch: CommitFact[] = []
for (const f of facts) {
if (f.generation <= committedGeneration) continue
if (f.generation <= lastGen) {
throw new Error(
`fact log: streamFactsAbove found non-ascending generations ` +
`(${f.generation} after ${lastGen} in ${file}) — refusing to replay out of order`
)
}
lastGen = f.generation
batch.push(f)
}
if (batch.length > 0) yield batch
}
}
async peekFactsAbove(committedGeneration: number): Promise<CommitFact[]> {
const stored = (await this.storage.readRawObject(FACTS_MANIFEST_PATH)) as FactsManifest | null
if (!stored || typeof stored !== 'object' || !Array.isArray(stored.segments)) return []

View file

@ -637,63 +637,33 @@ export class GenerationStore {
this.foldCheckpointChainValid = checkpoint !== null || this.committed === 0
this.foldCheckpoint = foldBound
if (uncleanOpen) this.foldCheckpointChainValid = true
// THE FOLD STREAMS AND NARRATES. A production first boot after a live
// flip folded ~7k facts by materializing them all (GBs of decoded
// after-images, a GC storm, a starved write lane) in SILENCE — the
// operator restarted the process three times mid-fold, each restart
// making the next boot unclean again. Two laws from that day: the
// fold consumes the log one segment-batch at a time (memory = one
// segment, any log size), and it announces itself BEFORE the work
// with progress lines DURING it — an operator who can see a fold
// converging lets it finish.
const foldKind = uncleanOpen
? foldBound > 0
? `BOUNDED fold above checkpoint ${foldBound}`
: 'WHOLE-LOG fold'
: 'above-manifest replay'
let replayed = 0
const replayFact = async (fact: CommitFact): Promise<void> => {
for (const op of fact.ops) {
const image =
op.record === null
? { metadata: null, vector: null }
: { metadata: op.record.metadata, vector: op.record.vector }
if (op.kind === 'verb') await this.storage.writeVerbRaw(op.id, image)
else await this.storage.writeNounRaw(op.id, image)
this.noteCheckpointDirty(op.kind, op.id)
const factsToReplay = uncleanOpen
? await this.factLog.peekFactsAbove(foldBound)
: orphans
if (factsToReplay.length > 0) {
let replayed = 0
for (const fact of factsToReplay) {
for (const op of fact.ops) {
const image =
op.record === null
? { metadata: null, vector: null }
: { metadata: op.record.metadata, vector: op.record.vector }
if (op.kind === 'verb') await this.storage.writeVerbRaw(op.id, image)
else await this.storage.writeNounRaw(op.id, image)
this.noteCheckpointDirty(op.kind, op.id)
}
replayed++
if (fact.generation > this.committed) {
this.committed = fact.generation
this.appendCommittedGen(fact.generation)
this.setDelta(fact.generation, {
nouns: new Set(fact.ops.filter((o) => o.kind === 'noun').map((o) => o.id)),
verbs: new Set(fact.ops.filter((o) => o.kind === 'verb').map((o) => o.id)),
timestamp: fact.timestamp,
bytes: 0
})
}
}
replayed++
if (replayed % 1000 === 0) {
prodLog.warn(
`[GenerationStore] recovery fold in progress — ${replayed} fact(s) folded ` +
`(at generation ${fact.generation}); do not restart, the fold is finite`
)
}
if (fact.generation > this.committed) {
this.committed = fact.generation
this.appendCommittedGen(fact.generation)
this.setDelta(fact.generation, {
nouns: new Set(fact.ops.filter((o) => o.kind === 'noun').map((o) => o.id)),
verbs: new Set(fact.ops.filter((o) => o.kind === 'verb').map((o) => o.id)),
timestamp: fact.timestamp,
bytes: 0
})
}
}
if (uncleanOpen) {
prodLog.warn(
`[GenerationStore] log-authority recovery: ${foldKind} beginning ` +
`(unclean shutdown detected) — streaming replay, bounded memory, ` +
`progress every 1000 facts. Do not restart the process; a restart ` +
`re-pays the whole fold.`
)
for await (const batch of this.factLog.streamFactsAbove(foldBound)) {
for (const fact of batch) await replayFact(fact)
}
} else {
for (const fact of orphans) await replayFact(fact)
}
if (replayed > 0) {
if (this.counter < this.committed) this.counter = this.committed
await this.persistCounterUnlocked()
const manifest: GenerationManifest = {
@ -706,7 +676,13 @@ export class GenerationStore {
await this.storage.syncRawObjects([MANIFEST_PATH])
prodLog.warn(
`[GenerationStore] log-authority recovery replayed ${replayed} fact(s) into ` +
`canonical (${foldKind}; committed at ${this.committed}) — an acked write is never lost`
`canonical (${
uncleanOpen
? foldBound > 0
? `BOUNDED fold above checkpoint ${foldBound} — unclean shutdown`
: 'WHOLE-LOG fold — unclean shutdown'
: 'above-manifest'
}; committed at ${this.committed}) an acked write is never lost`
)
}
// A recovery fold re-applied (and the barrier below re-syncs) every
@ -921,44 +897,6 @@ export class GenerationStore {
this.authorityIsLog = true
}
/** Whether the fold-checkpoint chain is armed (a bounded fold is possible). */
foldCheckpointChainArmed(): boolean {
return this.foldCheckpointChainValid
}
/**
* @description Stamp the fold checkpoint after the caller has completed a
* FULL canonical barrier (every live row's canonical bytes fsynced, paged
* the adoption path does this right after a non-fresh flip). The stamp
* asserts total coverage, so it may ONLY be called when the barrier walked
* everything; stamp-after-data is the caller's ordering to keep. Arms the
* chain: the brain's first unclean boot folds (checkpoint, head] instead of
* the whole log a production first boot after a live flip paid a full-log
* fold through three mid-fold restarts because the chain could previously
* only arm at a crash.
*/
async stampFoldCheckpointAfterFullBarrier(): Promise<void> {
return this.withMutex(async () => {
if (!this.authorityIsLog || !this.factLog) {
throw new Error(
'stampFoldCheckpointAfterFullBarrier: only a log-authority brain stamps a fold checkpoint'
)
}
this.foldCheckpointChainValid = true
// The full barrier supersedes any accumulated partial set.
this.checkpointDirtyNouns = new Set()
this.checkpointDirtyVerbs = new Set()
const target = this.committed
await this.storage.writeRawObject(FOLD_CHECKPOINT_PATH, { generation: target })
await this.storage.syncRawObjects([FOLD_CHECKPOINT_PATH])
this.foldCheckpoint = target
prodLog.info(
`[GenerationStore] fold checkpoint founded at generation ${target}` +
`crash recovery is bounded from this moment`
)
})
}
/**
* @description Adoption-time chain bootstrap, abort called when an
* adoption attempt throws or refuses after phase 1. Disarms the chain and

View file

@ -161,38 +161,6 @@ describe('fold-checkpoint bound — crash recovery folds (checkpoint, head], nev
expect(stamped, 'the first whole-log fold is the chains base case — it stamps').toBe(committedOf(reopened))
}, 120000)
it('ARM-AT-FLIP: a non-fresh adoption founds the checkpoint immediately — the first post-flip boot folds BOUNDED, never whole-log', async () => {
const dir = trackDir()
// The production shape: a brain with history flips LIVE (no crash ever).
const brain = await openBrain(dir, { logAuthority: 'defer' })
liveBrains.push(brain)
const preFlip = await brain.add({ data: 'pre-flip resident', type: NounType.Document, metadata: { era: 'tree' } })
await brain.flush()
expect(readCheckpoint(dir), 'no checkpoint before the flip').toBeNull()
const report = await brain.adoptLogAuthority()
expect(report.verdict).toBe('green')
// THE PIN: the flip itself founded the checkpoint — no crash required.
const founded = readCheckpoint(dir)
expect(founded, 'checkpoint founded at flip').toBe(committedOf(brain))
// First post-flip boot, unclean (the production first-restart shape):
// a post-flip write above the checkpoint is restored FROM ITS AT-ACK FACT
// (deliberately NOT flushed — a flush would barrier-sync it and advance
// the stamp over it, making its loss synthetic); the pre-flip row (its
// baseline fact ≤ checkpoint, its bytes barrier-synced at the flip) is
// OUTSIDE the fold — vaporizing it synthetically proves the bound.
const postFlip = await brain.add({ data: 'post-flip write', type: NounType.Document, metadata: { era: 'log' } })
await abandonAsCrashed(liveBrains.pop()!)
dropCanonicalNoun(dir, preFlip)
dropCanonicalNoun(dir, postFlip)
const reopened = await openBrain(dir, { logAuthority: 'adopt' })
liveBrains.push(reopened)
expect(await reopened.get(postFlip), 'above-checkpoint fact re-applied').not.toBeNull()
expect(await reopened.get(preFlip), 'below-checkpoint fact skipped — the fold is bounded on the FIRST post-flip boot').toBeNull()
}, 240000)
it('a tree-authority brain never stamps a checkpoint', async () => {
const dir = trackDir()
const brain = await openBrain(dir, { logAuthority: 'defer' })