Skip to main content

Store

Struct Store 

Source
pub struct Store { /* private fields */ }

Implementations§

Source§

impl Store

Source

pub fn open(root: impl AsRef<Path>) -> Result<Self, StoreError>

Open or create a store rooted at root.

Source

pub fn root(&self) -> &Path

Source

pub fn publish(&self, stage: &Stage) -> Result<String, StoreError>

Publish a stage as Draft. Returns the StageId. Idempotent: republishing the same canonical AST returns the same StageId without writing duplicates.

Source

pub fn publish_signed( &self, stage: &Stage, signer: Option<&Keypair>, ) -> Result<String, StoreError>

Like Self::publish but optionally attaches an Ed25519 signature over the StageId (#227). When signer is Some, the persisted metadata gets a signature field that downstream consumers can verify via lex_vcs::verify_stage_id.

Idempotency: if a metadata file already exists the signature is not re-written. This preserves “republishing is a no-op” even across different signers — promoting a signed stage requires a fresh stage hash anyway, so a metadata overwrite would be the wrong primitive.

Source

pub fn activate(&self, stage_id: &str) -> Result<(), StoreError>

Source

pub fn deprecate( &self, stage_id: &str, reason: impl Into<String>, ) -> Result<(), StoreError>

Source

pub fn tombstone(&self, stage_id: &str) -> Result<(), StoreError>

Source

pub fn resolve_sig(&self, sig: &str) -> Result<Option<String>, StoreError>

The current Active StageId for a signature, or None.

Source

pub fn sig_history( &self, sig: &str, ) -> Result<Vec<StageHistoryEntry>, StoreError>

Per-stage history for a SigId, ordered chronologically by the last transition timestamp. Returns one entry per distinct StageId that has ever been published under sig. Ok(vec![]) if the SigId doesn’t exist in the store.

Used by lex blame to render “where does this fn come from”.

Source

pub fn get_ast(&self, stage_id: &str) -> Result<Stage, StoreError>

Source

pub fn get_metadata(&self, stage_id: &str) -> Result<Metadata, StoreError>

Source

pub fn get_status(&self, stage_id: &str) -> Result<StageStatus, StoreError>

Source

pub fn list_stages_by_name(&self, name: &str) -> Result<Vec<String>, StoreError>

Source

pub fn list_sigs(&self) -> Result<Vec<String>, StoreError>

Source

pub fn attach_test(&self, sig: &str, test: &Test) -> Result<String, StoreError>

Source

pub fn list_tests(&self, sig: &str) -> Result<Vec<Test>, StoreError>

Source

pub fn attach_spec(&self, sig: &str, spec: &Spec) -> Result<String, StoreError>

Source

pub fn list_specs(&self, sig: &str) -> Result<Vec<Spec>, StoreError>

Source

pub fn save_trace(&self, tree: &TraceTree) -> Result<String, StoreError>

Source

pub fn load_trace(&self, run_id: &str) -> Result<TraceTree, StoreError>

Source

pub fn list_traces(&self) -> Result<Vec<String>, StoreError>

Source

pub fn publish_program( &self, branch: &str, stages: &[Stage], diff: &DiffReport, new_imports: &ImportMap, activate: bool, ) -> Result<PublishOutcome, StoreError>

Apply a published program to a branch as a sequence of typed operations. Returns the ordered list of op_ids + the new head_op. The caller (lex publish CLI, lex serve’s HTTP handler) is responsible for computing the DiffReport against the current branch head — the diff infrastructure lives in lex-vcs::compute_diff (previously lex-cli) to keep this layer from owning diffing logic.

On success: every op in the returned list is durable in the op log and the branch’s head_op points at the last one. On a no-op (no diff): returns empty ops and the existing head_op unchanged.

Source

pub fn publish_program_signed( &self, branch: &str, stages: &[Stage], diff: &DiffReport, new_imports: &ImportMap, activate: bool, signer: Option<&Keypair>, ) -> Result<PublishOutcome, StoreError>

Signed variant of Self::publish_program (#227). Every stage written under this batch gets the same signer; per-stage keys aren’t supported because the agent identity model treats a publish as a single authorial act.

Source

pub fn derive_imports_from_oplog( &self, branch: &str, ) -> Result<ImportMap, StoreError>

Source

pub fn apply_operation_checked( &self, branch: &str, op: Operation, transition: StageTransition, candidate: &[Stage], ) -> Result<OpId, StoreError>

Apply an operation to a branch and advance its head_op.

The single advance path. Validates parents via lex_vcs::apply, persists the operation via the op log, then atomically advances the branch file’s head_op via set_branch_head_op.

Errors:

  • UnknownBranch: branch does not exist (no op is persisted).
  • Apply(ApplyError::StaleParent): the op’s parents don’t match the branch head — head is unchanged. Callers that want retry-on-stale (e.g. lex publish re-running against a moved head) match on this variant explicitly.
  • Apply(ApplyError::UnknownMergeParent): a merge op’s second parent isn’t in the log.
  • Io: filesystem error during persist or branch advance.

Crash recovery: between op persist and branch advance, a crash can leave an orphan op record in the log with no branch pointing at it. The op is content-addressed and cheap to re-derive from the same source. See Apply a single op against branch, gated on the candidate program typechecking. The per-op variant of #130’s write-time gate — counterpart to Self::publish_program’s batch-mode check.

candidate is the sequence of Stages that would exist on this branch after the op is applied. Caller’s responsibility: today neither lex-store nor lex-vcs reconstruct the candidate from the op + branch state on behalf of the caller. The natural callers (HTTP POST /v1/publish for a single op; agent harnesses driving merges via the future #134 API) already have the candidate in memory.

On rejection: branch head unchanged, no op record persisted. Same atomicity guarantee as the publish path.

§Why a separate method, not a flag on apply_operation

The merge engine in lex-vcs::merge calls Store::apply_operation directly to land merge ops, and at merge time the resolved program isn’t a single Vec<Stage> the way it is on the publish path — it’s a per-sig resolution map. Forcing a candidate through apply_operation would either require the merge engine to assemble one (slow, every active stage off disk) or accept Option<&[Stage]> and silently skip the gate — the second is exactly the kind of “secretly opt-out” path #130 is trying to remove. The honest split is two methods: apply_operation for callers that already typecheck their inputs (or don’t need to — rare, but the merge-resolve case), apply_operation_checked for everyone else.

Source

pub fn attestation_log(&self) -> Result<AttestationLog, StoreError>

Open the attestation log rooted at this store. The log lives under <root>/attestations/; opening is idempotent and cheap (fs::create_dir_all). Exposed publicly so consumers — lex blame --with-evidence, GET /v1/stage/<id>/attestations — can read what the store gate emitted without round-tripping through this crate’s API surface.

Source

pub fn apply_operation( &self, branch: &str, op: Operation, transition: StageTransition, ) -> Result<OpId, StoreError>

set_branch_head_op for the durability story on the branch file itself.

Source§

impl Store

Source

pub fn current_branch(&self) -> String

Source

pub fn set_current_branch(&self, name: &str) -> Result<(), StoreError>

Source

pub fn list_branches(&self) -> Result<Vec<String>, StoreError>

Source

pub fn get_branch(&self, name: &str) -> Result<Option<Branch>, StoreError>

Source

pub fn branch_head( &self, name: &str, ) -> Result<BTreeMap<String, String>, StoreError>

Computed view: walk the op log from the branch head and replay each transition into a SigId → StageId map.

PERF: O(N) per call where N is the number of ops on this branch’s history. Each call: re-opens the op log (a mkdir -p ops/ syscall), BFS-walks the full ancestor set, allocates a BTreeSet<OpId> + Vec<OperationRecord> + BTreeMap, reverses, then linearly replays. No memoization. Tier-1 size (a few hundred ops per branch) makes this acceptable; if hotter consumers land (e.g. an HTTP-served branch_head), memoize per-(branch_name, head_op) — the head_op tail of the cache key is a content-addressed hash, so cache invalidation is free.

Source

pub fn branch_log(&self, name: &str) -> Result<Vec<MergeRecord>, StoreError>

Source

pub fn create_branch(&self, name: &str, from: &str) -> Result<(), StoreError>

Snapshot the source branch’s head_op into a new named branch.

Source

pub fn create_predicate_branch( &self, name: &str, predicate: Value, ) -> Result<(), StoreError>

Create a predicate-defined branch (#133). The branch’s content is the set of ops matching predicate; head_op stays None and is materialized lazily by callers when they need a single point to apply ops against. Cheap to create and discard — it’s a saved query, not a snapshot.

Source

pub fn delete_branch(&self, name: &str) -> Result<(), StoreError>

Source§

impl Store

Source

pub fn merge(&self, src: &str, dst: &str) -> Result<MergeReport, StoreError>

Source

pub fn commit_merge( &self, dst: &str, report: &MergeReport, ) -> Result<(), StoreError>

Auto Trait Implementations§

§

impl Freeze for Store

§

impl RefUnwindSafe for Store

§

impl Send for Store

§

impl Sync for Store

§

impl Unpin for Store

§

impl UnsafeUnpin for Store

§

impl UnwindSafe for Store

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.