pub struct IngestLedger { /* private fields */ }Expand description
Content-hash idempotency ledger for zeph knowledge ingest.
Records (source_uri, content_hash) pairs of inputs that have been successfully embedded so
that unchanged files are skipped on the next run (spec-067 INV-5).
This is a re-read / cost guard only — it does NOT reconcile LLM extraction drift across
model versions (INV-5). An unchanged (source_uri, content_hash) pair skips re-embedding; a
changed hash for the same URI is treated as a new input and produces a new ledger row while
leaving any previous Qdrant chunks in place (stale-point cleanup is Phase 2).
Implementations§
Source§impl IngestLedger
impl IngestLedger
Sourcepub fn new(pool: DbPool) -> Self
pub fn new(pool: DbPool) -> Self
Creates a new IngestLedger wrapping the given database pool.
The pool should come from SemanticMemory::sqlite().pool().clone() so the ledger shares
the agent’s existing connection pool rather than opening a new file.
Sourcepub fn content_hash(bytes: &[u8]) -> String
pub fn content_hash(bytes: &[u8]) -> String
Computes the BLAKE3 hex digest of bytes.
This is the canonical content-hash format used as the content_hash column value.
Callers must use this function (rather than a different hash algorithm or encoding) to
ensure ledger keys are consistent across invocations.
§Examples
use zeph_memory::graph::ingest::IngestLedger;
let hash = IngestLedger::content_hash(b"hello world");
assert_eq!(hash.len(), 64, "BLAKE3 hex digest is always 64 characters");Sourcepub async fn is_ingested(
&self,
source_uri: &str,
content_hash: &str,
) -> Result<bool, MemoryError>
pub async fn is_ingested( &self, source_uri: &str, content_hash: &str, ) -> Result<bool, MemoryError>
Returns true if the (source_uri, content_hash) pair is already recorded in the ledger.
When this returns true, the caller should skip re-embedding the input — its content has
not changed since it was last ingested (spec-067 FR-012).
§Errors
Returns MemoryError::Sqlx on database failure.
Sourcepub async fn mark_ingested(
&self,
source_uri: &str,
content_hash: &str,
batch_id: &str,
entities: i64,
edges: i64,
) -> Result<(), MemoryError>
pub async fn mark_ingested( &self, source_uri: &str, content_hash: &str, batch_id: &str, entities: i64, edges: i64, ) -> Result<(), MemoryError>
Records a successful ingest of (source_uri, content_hash).
Idempotent: if the pair already exists the row is updated in place with the new
batch_id, ingested_at, entities, and edges values
(ON CONFLICT … DO UPDATE).
entities and edges should be 0 for the notes sink (Phase 1). Non-zero values are
reserved for Phase 2 graph extraction.
§Errors
Returns MemoryError::Sqlx on database failure.
Sourcepub async fn batch_exists(&self, batch_id: &str) -> Result<bool, MemoryError>
pub async fn batch_exists(&self, batch_id: &str) -> Result<bool, MemoryError>
Returns true if any row in the ledger has the given import_batch_id.
§Errors
Returns MemoryError::Sqlx on database failure.
Sourcepub async fn resolve_batch_id(
&self,
prefix: &str,
) -> Result<BatchIdResolution, MemoryError>
pub async fn resolve_batch_id( &self, prefix: &str, ) -> Result<BatchIdResolution, MemoryError>
Resolves a (possibly abbreviated) batch_id prefix to a full import_batch_id.
Mirrors git’s unambiguous short-hash resolution: an exact match on a full id wins
immediately; otherwise a prefix that uniquely identifies one batch resolves to it, a
prefix shared by several batches is reported as BatchIdResolution::Ambiguous, and a
prefix matching no batch is reported as BatchIdResolution::NotFound. This lets
zeph knowledge rollback --batch-id accept the 8-character prefix printed by
zeph knowledge status (#5399).
An empty (or whitespace-only) prefix always resolves to BatchIdResolution::NotFound,
even when the ledger is non-empty — every id trivially starts_with(""), so without this
guard a blank prefix (e.g. an unset --batch-id "$VAR" shell substitution) would silently
resolve to the sole batch in a single-batch ledger instead of being rejected.
§Errors
Returns MemoryError::Sqlx on database failure.
Sourcepub async fn delete_batch(&self, batch_id: &str) -> Result<u64, MemoryError>
pub async fn delete_batch(&self, batch_id: &str) -> Result<u64, MemoryError>
Deletes all ledger rows for the given import_batch_id.
Returns the number of rows removed.
§Errors
Returns MemoryError::Sqlx on database failure.
Sourcepub async fn delete_batch_in_tx(
&self,
batch_id: &str,
tx: &mut DbTransaction<'_>,
) -> Result<u64, MemoryError>
pub async fn delete_batch_in_tx( &self, batch_id: &str, tx: &mut DbTransaction<'_>, ) -> Result<u64, MemoryError>
Deletes all ledger rows for batch_id within a caller-provided transaction.
Executes the same DELETE as Self::delete_batch but uses tx so the caller can
combine it with other writes in a single atomic unit.
Returns the number of rows removed.
§Errors
Returns MemoryError::Sqlx on database failure.
Sourcepub async fn summary(&self) -> Result<Vec<LedgerEntry>, MemoryError>
pub async fn summary(&self) -> Result<Vec<LedgerEntry>, MemoryError>
Returns all ledger rows ordered by ingested_at descending, newest first.
This is the data source for zeph knowledge status.
§Errors
Returns MemoryError::Sqlx on database failure.
Trait Implementations§
Source§impl Clone for IngestLedger
impl Clone for IngestLedger
Source§fn clone(&self) -> IngestLedger
fn clone(&self) -> IngestLedger
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl !RefUnwindSafe for IngestLedger
impl !UnwindSafe for IngestLedger
impl Freeze for IngestLedger
impl Send for IngestLedger
impl Sync for IngestLedger
impl Unpin for IngestLedger
impl UnsafeUnpin for IngestLedger
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request