feat: provider access to the fact log + shared stamp verifier via internals
Three additive surfaces for native index providers, which hold only `storage` and must never construct their own fact-log reader (the log's open path is writer-side — it reconciles by truncating/rewriting): - Fact-scan capability on the storage adapter (the getBinaryBlobPath pattern): the host brain wires a closure over its LIVE fact log at init; providers call storage.scanFacts()/factLogHeadGeneration()/ factSegmentPaths() and fall back to the enumeration walk on null. Restore/reopen swaps the underlying log transparently. - The family-stamp trio (readFamilyStamp/writeFamilyStamp/ verifyFamilyStamp + types) exported from @soulcraft/brainy/internals, so 'one verifier' is literally one function shared with the native side, never two synchronized copies. - Rollup invariants widened to number|string: content fingerprints (e.g. a per-tree SHA-256) are valid invariant values; strict equality either way, and a type mismatch reads as incoherence, never a pass.
This commit is contained in:
parent
70886da548
commit
352e356fd5
7 changed files with 153 additions and 3 deletions
|
|
@ -842,6 +842,46 @@ export abstract class BaseStorage extends BaseStorageAdapter {
|
|||
return this.deleteObjectFromPath(path)
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// Fact-scan capability — the seam through which an index provider holding
|
||||
// only `storage` reaches the generation fact log. The HOST brain wires the
|
||||
// source at init (a closure over its live fact log, so restore/reopen stays
|
||||
// transparent); providers call storage.scanFacts?.(...) and fall back to the
|
||||
// enumeration walk when it returns null. Providers never construct a
|
||||
// fact-log reader themselves — the log's open path is writer-side.
|
||||
// ==========================================================================
|
||||
|
||||
/** The host-wired fact-scan source (a closure over the live fact log). */
|
||||
private _factScanSource: (() => import('../db/factLog.js').FactLog | null) | null = null
|
||||
|
||||
/** HOST-ONLY: wire (or clear) the fact-scan capability's source. */
|
||||
public setFactScanSource(source: (() => import('../db/factLog.js').FactLog | null) | null): void {
|
||||
this._factScanSource = source
|
||||
}
|
||||
|
||||
/** Open a scan over committed facts, or `null` when no fact log exists. */
|
||||
public scanFacts(options?: {
|
||||
fromGeneration?: number
|
||||
toGeneration?: number
|
||||
kinds?: Array<'noun' | 'verb'>
|
||||
batchSize?: number
|
||||
}): import('../db/factLog.js').FactScanHandle | null {
|
||||
const log = this._factScanSource?.()
|
||||
return log ? log.scanFacts(options) : null
|
||||
}
|
||||
|
||||
/** The fact log's head generation, or `null` when no fact log exists. */
|
||||
public factLogHeadGeneration(): number | null {
|
||||
const log = this._factScanSource?.()
|
||||
return log ? log.headGeneration() : null
|
||||
}
|
||||
|
||||
/** Sealed fact-segment paths (zero-copy handoff); empty when none. */
|
||||
public factSegmentPaths(options?: { fromGeneration?: number }): string[] {
|
||||
const log = this._factScanSource?.()
|
||||
return log ? log.segmentPaths(options) : []
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Remove the container that held a canonical entity's leg files,
|
||||
* called after both legs are deleted so a delete leaves NOTHING behind — no
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue