Skip to main content

OpRecord

Enum OpRecord 

Source
pub enum OpRecord {
Show 24 variants Snapshot { new_state: StateId, prev_head: Option<StateId>, head: Option<StateId>, thread: Option<String>, }, Goto { target: StateId, prev_head: Option<StateId>, head: StateId, }, ThreadCreate { name: String, state: StateId, manager_snapshot: Option<Vec<u8>>, }, ThreadDelete { name: String, state: StateId, }, ThreadUpdate { name: String, old_state: StateId, new_state: StateId, manager_snapshots: Option<ThreadUpdateSnapshots>, }, Fork { from: StateId, new_state: StateId, thread: Option<String>, head: Option<StateId>, }, Collapse { sources: Vec<StateId>, result: StateId, thread: Option<String>, pre_thread_state: Option<StateId>, }, MarkerCreate { name: String, state: StateId, }, MarkerDelete { name: String, state: StateId, }, Checkpoint { parent: Option<StateId>, state: StateId, thread: Option<String>, }, TransactionAbort { transaction_id: String, reason: String, }, EphemeralThreadCollapse { thread: String, final_state: StateId, }, ConflictResolved { conflict_id: String, resolution: String, resolver: Attribution, mode: ConflictResolutionMode, }, TransactionCommit { transaction_id: String, op_count: u32, }, Redact { redaction_id: ContentHash, blob: ContentHash, state: StateId, path: String, }, Purge { redaction_id: ContentHash, blob: ContentHash, }, FastForward { source_thread: String, target_thread: String, pre_target_id: StateId, post_target_id: StateId, }, GitCheckpoint { branch: String, state: StateId, previous_git_oid: Option<String>, new_git_oid: String, }, RemoteThreadUpdate { remote: String, thread: String, state: StateId, }, RemoteThreadDelete { remote: String, thread: String, state: StateId, }, UndoRecoveryUpdate { state: StateId, }, StateVisibilitySet { state: StateId, record_id: ContentHash, tier: VisibilityTier, prior_sidecar: Option<Vec<u8>>, new_sidecar: Option<Vec<u8>>, }, StateVisibilityPromote { state: StateId, superseded: ContentHash, record_id: ContentHash, tier: VisibilityTier, prior_sidecar: Option<Vec<u8>>, new_sidecar: Option<Vec<u8>>, }, HeadUpdate { previous: RecordedHead, new: RecordedHead, },
}
Expand description

Record of an operation that can be undone.

Variants must be appended at the tail. rmp-serde encodes enum variants by discriminant index, so reordering or inserting in the middle would break every pre-existing on-disk oplog entry.

Variants§

§

Snapshot

Snapshot operation.

Fields

§new_state: StateId
§prev_head: Option<StateId>
§head: Option<StateId>

Detached HEAD published by this snapshot, if any. Attached snapshots publish their thread ref instead; detached snapshots publish HEAD = Detached(head).

§thread: Option<String>
§

Goto

Goto operation.

Fields

§target: StateId
§prev_head: Option<StateId>
§head: StateId

HEAD published by this goto. This intentionally duplicates target for the current detached-only command shape so crash replay folds the published ref state directly instead of inferring it from intent.

§

ThreadCreate

Thread creation.

manager_snapshot is opaque rmp-serde bytes of the Thread record body. Opaque to keep the oplog crate independent of repo-level types; the repo crate owns the encoding via ThreadManager::snapshot_thread_record / ThreadManager::decode_thread_record_snapshot. None for callsites that don’t write a ThreadManager record alongside the op (rename batch’s new-name arm, ingest, harness/agent stubs).

Fields

§name: String
§state: StateId
§manager_snapshot: Option<Vec<u8>>

rmp-serde-encoded Thread record body, or None when no record was written by the forward path.

§

ThreadDelete

Thread deletion.

Fields

§name: String
§state: StateId
§

ThreadUpdate

Thread update.

Fields

§name: String
§old_state: StateId
§new_state: StateId
§manager_snapshots: Option<ThreadUpdateSnapshots>

rmp-serde-encoded Thread record bodies around the update.

This is intentionally one sparse tail field rather than two independently-skipped fields: rmp-serde encodes enum variant fields positionally, so skipping only the old slot would shift the new snapshot into the old position for older readers.

§

Fork

Fork operation.

from is the source state forked from; new_state is the fork result. thread/head name the ref the fork published so a crash-replay (oplog committed, ref not yet materialized) can re-derive which ref to publish (heddle#330 write chokepoint): thread = Some(name) when the fork attached HEAD to a new thread, head = Some(state) when it detached HEAD at the fork result. These published-ref fields — not the from/new_state positional pair — are the authoritative replay/materialization target.

Fields

§from: StateId
§new_state: StateId
§thread: Option<String>
§

Collapse

Collapse operation. thread names the published ref: Some(name) when the collapse published a thread ref, None when it published a detached HEAD at result (heddle#330 write chokepoint — the published-ref discriminant replay needs to materialize the ref).

Fields

§sources: Vec<StateId>
§result: StateId
§thread: Option<String>
§pre_thread_state: Option<StateId>
§

MarkerCreate

Marker creation.

Fields

§name: String
§state: StateId
§

MarkerDelete

Marker deletion.

Fields

§name: String
§state: StateId
§

Checkpoint

Cheap addressable save intended for agent-style frequent saves. Distinct from Snapshot so heddle log --no-checkpoints (the human default) can filter them without losing the ability to goto them.

Fields

§parent: Option<StateId>
§state: StateId
§thread: Option<String>
§

TransactionAbort

Recorded when a transaction is aborted. The buffered ops the transaction would have applied are listed for forensic replay; no state was actually committed.

Fields

§transaction_id: String
§reason: String
§

EphemeralThreadCollapse

Recorded when an ephemeral thread’s TTL elapses and it auto-collapses. The states behind the thread remain addressable; only the thread pointer is retired.

Fields

§thread: String
§final_state: StateId
§

ConflictResolved

Recorded when a structured conflict is resolved through ConflictService::Resolve (or its CLI front-end). Carries the addressable conflict id rather than the path so agents can correlate across calls.

Fields

§conflict_id: String
§resolution: String
§resolver: Attribution

Principal and optional agent that performed or initiated the resolution, using the same shape as state authorship.

§

TransactionCommit

Recorded when a transaction is successfully committed. The number of buffered ops at commit time is captured so the audit trail shows how much work was folded in (real per-op replay is the next follow-on; today it is the count, not the records).

Fields

§transaction_id: String
§op_count: u32
§

Redact

A redaction was declared on a blob in a specific state. The blob bytes are still on disk; readers see the stub from the Redaction object instead.

Reversible via heddle undo --allow-redact-undo. The inverse removes the specific Redaction record from the per-blob sidecar so subsequent materializes restore the original bytes. The opt-in flag exists because the inverse re-exposes previously-hidden content; a casual heddle undo chain refuses rather than silently unwind the stub-substitution.

Refused regardless of the flag when the underlying bytes have since been purged: the Redaction record is then load-bearing audit trail for “these bytes were physically destroyed”, and removing it would lie about local storage. Purge itself is irreversible.

Redo is not supported. The OpRecord doesn’t preserve the full Redaction (reason, redactor, signature, …), so heddle redo of an undone Redact refuses with a clear message rather than silently no-op. Re-run heddle redact apply to recreate.

Fields

§redaction_id: ContentHash

Content hash of the encoded Redaction object.

§blob: ContentHash

Blob the redaction targets.

§state: StateId

State that surfaces the redacted file.

§path: String

Path within the state’s tree.

§

Purge

The underlying blob bytes referenced by an earlier redaction were physically removed from local storage. The Redaction record is preserved; only the bytes are gone. Non-reversible by design — heddle undo on a Purge fails with a clear message.

Fields

§redaction_id: ContentHash

Content hash of the Redaction whose bytes were purged.

§blob: ContentHash

Blob hash whose bytes were physically removed.

§

FastForward

Fast-forward merge: target_thread advanced from pre_target_id to post_target_id (the source’s tip at the time of the FF) without writing a synthetic merge state. source_thread is untouched throughout.

Distinct from Goto so undo can restore both HEAD and the target thread ref. The Goto inverse only rewinds HEAD, which stranded the merged-into thread ref at the FF target — the bug closed by heddle#99 r1.

post_target_id makes redo deterministic: it replays the recorded operation byte-for-byte instead of re-resolving source_thread → tip at apply time. source_thread is kept for forensic context only — neither inverse reads it.

Fields

§source_thread: String

The thread that was merged in. Forensic-only — neither undo nor redo reads it.

§target_thread: String

The thread that fast-forwarded. Undo restores this ref to pre_target_id; redo advances it to post_target_id.

§pre_target_id: StateId

target_thread’s tip before the FF. Undo target.

§post_target_id: StateId

target_thread’s tip after the FF (the source’s tip at recording time). Redo target — recorded so replay is deterministic regardless of what source_thread does later.

§

GitCheckpoint

Git-overlay checkpoint written to the real Git checkout.

Fields

§branch: String
§state: StateId
§previous_git_oid: Option<String>
§new_git_oid: String
§

RemoteThreadUpdate

A remote-thread ref was published (heddle#330 r9). Before this variant set_remote_thread wrote the ref directly with no committed record, so reconciliation of the remote-thread class folded an empty tail. Recording the publish makes that reconciliation non-vacuous and lets crash-replay re-materialize the ref from its newest in-scope record.

Fields

§remote: String
§thread: String
§state: StateId
§

RemoteThreadDelete

A remote-thread ref was deleted (heddle#330 r9). Folded like a MarkerDelete: drops the name from the reconciled remote-thread set. state is the value at delete time (forensic context).

Fields

§remote: String
§thread: String
§state: StateId
§

UndoRecoveryUpdate

The heddle-internal pre-undo recovery pointer was set (heddle#330 r9). A single rolling ORIG_HEAD-style pointer with no delete path, so one update variant suffices. Local (per-checkout) ref — reconciles within its own op_scope.

Fields

§state: StateId
§

StateVisibilitySet

A visibility tier was declared on a state (heddle#317). Audit-trail companion to the per-state StateVisibility sidecar record: the sidecar is the authoritative effective tier; this oplog entry records who bound it and when. Emitted both by heddle visibility set and by the Invariant-A capture-time binding (spike #266 §5.4).

Reversible: prior_sidecar/new_sidecar carry the FULL per-state visibility sidecar bytes (or None for public-by-absence) immediately before and after the put. Undo restores prior_sidecar, redo restores new_sidecar — both absolute write-or-remove, mirroring the redaction sidecar capture-restore. Without the before-image the undo path could only no-op, leaving the oplog and the sidecar divergent (PR #529 P1).

Fields

§state: StateId
§record_id: ContentHash

Content id of the persisted StateVisibility record.

§tier: VisibilityTier

The tier declared.

§prior_sidecar: Option<Vec<u8>>

Full sidecar bytes before the put (None = public-by-absence). Undo target.

§new_sidecar: Option<Vec<u8>>

Full sidecar bytes after the put (None = public-by-absence). Redo target.

§

StateVisibilityPromote

A state’s visibility was promoted to a less-restrictive tier by appending a superseding StateVisibility record (heddle#317). Reversible the same way as StateVisibilitySet: prior_sidecar/new_sidecar snapshot the whole sidecar around the put.

Fields

§state: StateId
§superseded: ContentHash

The prior record this promotion supersedes.

§record_id: ContentHash

Content id of the new, superseding record.

§tier: VisibilityTier

The tier promoted to.

§prior_sidecar: Option<Vec<u8>>

Full sidecar bytes before the put (None = public-by-absence). Undo target.

§new_sidecar: Option<Vec<u8>>

Full sidecar bytes after the put (None = public-by-absence). Redo target.

§

HeadUpdate

A direct HEAD publish that is not already represented by a more specific operation such as Snapshot, Fork, Collapse, or Goto.

Both images are recorded so reconciliation can recover a committed but unpublished move and undo/redo can restore the exact attachment state.

Fields

§previous: RecordedHead

Implementations§

Source§

impl OpRecord

Source

pub fn conflict_resolved( conflict_id: impl Into<String>, resolver: Attribution, mode: ConflictResolutionMode, ) -> Self

Construct an attributed conflict-resolution event.

Source

pub fn description(&self) -> String

Get a short description of the operation.

Source§

impl OpRecord

Source

pub fn verb(&self) -> &'static str

The stable snake-case verb for this record’s variant. Exhaustive match — a new OpRecord variant fails to compile until it has a verb here. Verbs are shared across variants that fold to one concept.

Source

pub fn is_checkpoint_verb(&self) -> bool

True iff this is the agent-style OpRecord::Checkpoint that heddle log --no-checkpoints (the human default) and the daemon op-log query hide. New variants surface by default — only the catalog entries flagged checkpoint = true are hidden.

Source§

impl OpRecord

Source

pub fn verbs(include_checkpoints: bool) -> Vec<&'static str>

The deduped verb vocabulary. With include_checkpoints == false the agent checkpoint verb is dropped (the heddle log human default and the daemon op-log query’s default filter); every other verb — including any future variant — is surfaced. Derived from OP_VERB_CATALOG, so a new variant joins the vocabulary the moment it has a catalog entry, with no hand-maintained list to forget. Order follows variant declaration.

Source§

impl OpRecord

Per-variant undo/redo semantics, classified beside OpRecord so adding a variant updates these rules in one place rather than editing CLI safety matches (heddle#500, architecture-deepening C3). Each match enumerates every variant with no wildcard, so the compiler forces a new variant to declare its undo/redo semantics here.

Source

pub fn states_required_for_undo(&self) -> Vec<StateId>

State IDs the undo inverse must load from the object store. Variants whose undo is a no-op, only mutates sidecars/Git OIDs, or is irreversible return an empty list — they can’t trip a missing-state reachability check. Enumerated explicitly (no wildcard) so a new state-carrying variant must declare what its undo needs to load (heddle#354 r9).

Source

pub fn states_required_for_redo(&self) -> Vec<StateId>

State IDs the redo replay must load from the object store. Variants whose redo is a no-op, deletes a ref, or touches only sidecars/Git OIDs return an empty list. Enumerated explicitly so a new state-carrying variant must declare its redo target (heddle#354 r9).

Source

pub fn redo_unsupported_label(&self) -> Option<&'static str>

Label of the operation kind when this record has no faithful redo path, else None. Redact/Purge can’t be replayed — the OpRecord doesn’t preserve the full Redaction (reason, redactor, signature) and Purge is irreversible. Enumerated explicitly so a future variant without a redo path must be classified here (heddle#354 r9).

Source

pub fn redaction_undo_class(&self) -> RedactionUndoClass<'_>

This record’s role in undo’s redaction-safety preflight. Enumerated explicitly so a future redaction-adjacent variant must be classified here (heddle#354 r9).

Source

pub fn thread_worktree_undo_hazard_name(&self) -> Option<&str>

The thread name if undoing this record carries the worktree-orphan hazard — i.e. a thread-create whose inverse removes the ref, leaving any materialized worktree orphaned. None for every other record. Enumerated explicitly so a future worktree-creating variant must be classified here (heddle#354 r9).

Trait Implementations§

Source§

impl Clone for OpRecord

Source§

fn clone(&self) -> OpRecord

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for OpRecord

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for OpRecord

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for OpRecord

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

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

Source§

type Error = !

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.