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
Goto
Goto operation.
Fields
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
ThreadDelete
Thread deletion.
ThreadUpdate
Thread update.
Fields
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.
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
MarkerCreate
Marker creation.
MarkerDelete
Marker deletion.
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.
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.
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.
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
resolver: AttributionPrincipal and optional agent that performed or initiated the resolution, using the same shape as state authorship.
mode: ConflictResolutionModeTransactionCommit
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).
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: ContentHashContent hash of the encoded Redaction object.
blob: ContentHashBlob the redaction targets.
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: ContentHashContent hash of the Redaction whose bytes were purged.
blob: ContentHashBlob 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: StringThe thread that was merged in. Forensic-only — neither undo nor redo reads it.
GitCheckpoint
Git-overlay checkpoint written to the real Git checkout.
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.
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).
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.
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
record_id: ContentHashContent id of the persisted StateVisibility record.
tier: VisibilityTierThe tier declared.
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
superseded: ContentHashThe prior record this promotion supersedes.
record_id: ContentHashContent id of the new, superseding record.
tier: VisibilityTierThe tier promoted to.
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.
Implementations§
Source§impl OpRecord
impl OpRecord
Sourcepub fn conflict_resolved(
conflict_id: impl Into<String>,
resolver: Attribution,
mode: ConflictResolutionMode,
) -> Self
pub fn conflict_resolved( conflict_id: impl Into<String>, resolver: Attribution, mode: ConflictResolutionMode, ) -> Self
Construct an attributed conflict-resolution event.
Sourcepub fn description(&self) -> String
pub fn description(&self) -> String
Get a short description of the operation.
Source§impl OpRecord
impl OpRecord
Sourcepub fn verb(&self) -> &'static str
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.
Sourcepub fn is_checkpoint_verb(&self) -> bool
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
impl OpRecord
Sourcepub fn verbs(include_checkpoints: bool) -> Vec<&'static str>
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.
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.
Sourcepub fn states_required_for_undo(&self) -> Vec<StateId>
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).
Sourcepub fn states_required_for_redo(&self) -> Vec<StateId>
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).
Sourcepub fn redo_unsupported_label(&self) -> Option<&'static str>
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).
Sourcepub fn redaction_undo_class(&self) -> RedactionUndoClass<'_>
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).
Sourcepub fn thread_worktree_undo_hazard_name(&self) -> Option<&str>
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).