frame-state 0.2.0

Content-addressed state layer — haematite integration, entities, branching, cross-component references
Documentation
//! Durable, component-scoped state on haematite branches.
//!
//! [`ComponentStateStore`] is the only owner of haematite's wide capabilities:
//! its node store and branch/snapshot registries never leave this crate.
//! Components receive only [`ComponentStoreHandle`], which contains a component
//! identity, an incarnation fence, and a private reference back to the facade.
//! It accepts no branch name and can name a foreign component only through
//! capability-checked read resolution. Naming is not authority: a matching grant
//! row must be present at resolution time. The checkout view is created, read, and
//! dropped inside that call; the public surface returns only owned bytes and never
//! names [`haematite::ReadOnlyView`]. That published view's `put`, `delete`, and
//! `commit` methods all return [`haematite::CheckoutError::ReadOnly`], and no
//! mutable foreign branch can be obtained or re-derived in safe Rust. Haematite's
//! persisted [`BranchKind`](haematite::BranchKind) and lineage checks provide the
//! separate storage-enforced half of the boundary.
//!
//! A durable branch commit materialises only that branch's dirty shards, but its
//! `DiskStore` fsync barrier drains the shared store dirty set. Branches are
//! atomic commit units, not independent physical fsync domains. Coordination
//! across component namespaces is deliberately not a storage transaction.
//!
//! Durability grade (stack ruling, 2026-07-12): every "durable" in this crate
//! is **kill-9-verified and power-loss-fenced at the file level** (haematite
//! 7e7ab17, crash-tested). Known residual: a commit that creates a brand-new
//! prefix subdirectory does not fsync the store root's directory entry, so
//! power loss (not process kill) can vanish that subdirectory while the WAL
//! marker survives — and a fresh namespace's first commits sit exactly in that
//! window. The upstream fix is incident-class; this paragraph retires when its
//! crash pin lands. Until then, [`ComponentStateStore::reconcile`] treats a
//! branch ref without a readable store as a refused inconsistency — named
//! loudly, never silently healed.

mod archive;
mod codec;
mod engine;
mod error;
mod handle;
mod schema;
mod store;
mod types;

pub use error::{ReconcileInconsistency, StateError};
pub use handle::{ComponentStoreHandle, WorkStoreHandle};
pub use store::ComponentStateStore;
pub use types::{
    AbandonedWork, Archive, ComponentSchema, CrossComponentRef, EntityId, MergePolicy, MergeRecord,
    ReconcileAction, ReconcileReport, ReferenceTargetState,
};

/// Root hash of one committed component namespace.
pub use haematite::Hash as RootHash;

#[cfg(test)]
mod tests;