haematite-cli 0.21.7

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
Documentation
//! Fork origins are recorded at the branch's immutable roots.

use haematite::branch::ForkWrite;
use serde::{Deserialize, Serialize};

use super::{Captured, Failure, Storage, identifier, reads};
use crate::serve::protocol::Version;

const PROVENANCE_KEY: &[u8] = b"b\0fork";

#[derive(Debug, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ForkProvenance {
    pub branch: String,
    pub version: Version,
}

pub(super) fn provenance_write(
    writer: &haematite::db::branches::BranchDatabase,
    branch: &str,
    at: Version,
) -> Result<ForkWrite, Failure> {
    Ok(ForkWrite {
        shard_id: writer.shard_for(PROVENANCE_KEY),
        key: PROVENANCE_KEY.to_vec(),
        value: Some(
            serde_json::to_vec(&ForkProvenance {
                branch: branch.to_owned(),
                version: at,
            })
            .map_err(Failure::storage)?,
        ),
    })
}

pub(super) fn read_provenance(
    reader: &haematite::db::ReadOnlyDatabase,
    at: &Captured,
) -> Result<ForkProvenance, Failure> {
    provenance(reader, at)?.ok_or_else(|| {
        Failure::new(
            "fork_provenance_missing",
            "branch has no recorded fork origin",
        )
    })
}

/// The fork origin recorded at `at`'s roots, or `None` for a branch that was
/// not forked (STOR-003 HR1: a release reads it for every live branch).
pub(super) fn provenance(
    reader: &haematite::db::ReadOnlyDatabase,
    at: &Captured,
) -> Result<Option<ForkProvenance>, Failure> {
    let Some(bytes) = reads::get_bytes(reader, at, PROVENANCE_KEY)? else {
        return Ok(None);
    };
    let provenance: ForkProvenance = serde_json::from_slice(&bytes).map_err(Failure::storage)?;
    identifier(&provenance.branch)?;
    Ok(Some(provenance))
}

impl Storage {
    /// Read the explicit fork origin at the selected immutable roots.
    ///
    /// # Errors
    /// Refuses missing or invalid provenance and propagates storage failures.
    pub fn fork_provenance(&self, at: &Captured) -> Result<ForkProvenance, Failure> {
        read_provenance(&self.reader, at)
    }
}