Skip to main content
Import path: github.com/GustyCube/membrane/pkg/revision The revision package provides atomic, auditable operations for modifying the state of memory records. All operations are executed inside a single storage transaction so that partial revisions are never externally visible (RFC 15.7).
Episodic records are append-only and cannot be revised, forked, retracted, merged, or contested. All revision operations return ErrEpisodicImmutable when called on an episodic record.

Service

type Service struct { ... }

func NewService(store storage.Store) *Service
func NewServiceWithEmbedder(store storage.Store, embedder Embedder) *Service
Use NewServiceWithEmbedder to enable best-effort embedding generation for newly created records after each revision. Membrane.New picks the right constructor automatically.

Embedder interface

type Embedder interface {
    EmbedRecord(ctx context.Context, rec *schema.MemoryRecord) error
}

Supersede

func (s *Service) Supersede(
    ctx       context.Context,
    oldID     string,
    newRecord *schema.MemoryRecord,
    actor     string,
    rationale string,
) (*schema.MemoryRecord, error)
Atomically replaces oldID with newRecord. The old record is retracted (salience set to 0, semantic RevisionStatus set to retracted). The new record receives:
  • A supersedes relation pointing to the old record.
  • A ProvenanceSource referencing the old record.
  • For semantic payloads: Revision.Supersedes = oldID and Revision.Status = active.
Both records receive audit entries before the transaction commits.
oldID
string
required
ID of the record to replace.
newRecord
*schema.MemoryRecord
required
The replacement record. An ID is generated automatically if newRecord.ID is empty. Semantic records must include at least one evidence reference or provenance source.
actor
string
required
Identity of the actor performing the revision.
rationale
string
required
Human-readable explanation recorded in the audit log.
newRec := &schema.MemoryRecord{
    Type:        schema.MemoryTypeSemantic,
    Sensitivity: schema.SensitivityLow,
    Confidence:  0.95,
    Salience:    1.0,
    Payload: &schema.SemanticPayload{
        Kind:      "semantic",
        Subject:   "user:alice",
        Predicate: "prefers_language",
        Object:    "Rust",
        Validity:  schema.Validity{Mode: schema.ValidityModeGlobal},
        Evidence: []schema.ProvenanceRef{
            {SourceType: "observation", SourceID: "obs-001", Timestamp: time.Now()},
        },
    },
}

result, err := m.Supersede(ctx, oldRec.ID, newRec, "agent-core", "user corrected language preference")

Fork

func (s *Service) Fork(
    ctx          context.Context,
    sourceID     string,
    forkedRecord *schema.MemoryRecord,
    actor        string,
    rationale    string,
) (*schema.MemoryRecord, error)
Creates a new record derived from sourceID. Unlike Supersede, the source record remains active — both records coexist. The forked record receives a derived_from relation pointing to the source. Use Fork to create conditional variants of a fact or plan without invalidating the original.
sourceID
string
required
ID of the record to fork from.
forkedRecord
*schema.MemoryRecord
required
The new derived record. An ID is generated automatically if forkedRecord.ID is empty. Semantic records must include evidence.
actor
string
required
Identity of the actor performing the fork.
rationale
string
required
Human-readable explanation recorded in the audit log.
forked := &schema.MemoryRecord{
    Type:        schema.MemoryTypeSemantic,
    Sensitivity: schema.SensitivityLow,
    Confidence:  0.8,
    Salience:    1.0,
    Payload: &schema.SemanticPayload{
        Kind:      "semantic",
        Subject:   "user:alice",
        Predicate: "prefers_language",
        Object:    "Go",
        Validity: schema.Validity{
            Mode:       schema.ValidityModeConditional,
            Conditions: map[string]any{"context": "backend-work"},
        },
        Evidence: []schema.ProvenanceRef{
            {SourceType: "observation", SourceID: "obs-002", Timestamp: time.Now()},
        },
    },
}

result, err := m.Fork(ctx, sourceRec.ID, forked, "agent-core", "context-specific language preference")

Retract

func (s *Service) Retract(
    ctx       context.Context,
    id        string,
    actor     string,
    rationale string,
) error
Marks a record as retracted without deleting it. Salience is set to 0. For semantic records, Payload.Revision.Status is set to retracted. The record remains in storage for auditability.
id
string
required
ID of the record to retract.
actor
string
required
Identity of the actor performing the retraction.
rationale
string
required
Human-readable explanation recorded in the audit log.
err := m.Retract(ctx, rec.ID, "agent-core", "fact was found to be incorrect")

Merge

func (s *Service) Merge(
    ctx          context.Context,
    ids          []string,
    mergedRecord *schema.MemoryRecord,
    actor        string,
    rationale    string,
) (*schema.MemoryRecord, error)
Atomically combines multiple source records into a single merged record. All source records are retracted. The merged record receives a derived_from relation for each source, and each source receives a merge audit entry.
ids
[]string
required
IDs of the source records to merge. Must contain at least one entry.
mergedRecord
*schema.MemoryRecord
required
The consolidated record. An ID is generated automatically if mergedRecord.ID is empty. Semantic records must include evidence.
actor
string
required
Identity of the actor performing the merge.
rationale
string
required
Human-readable explanation recorded in the audit log.
merged := &schema.MemoryRecord{
    Type:        schema.MemoryTypeSemantic,
    Sensitivity: schema.SensitivityLow,
    Confidence:  0.9,
    Salience:    1.0,
    Payload: &schema.SemanticPayload{
        Kind:      "semantic",
        Subject:   "user:alice",
        Predicate: "preferred_stack",
        Object:    map[string]any{"lang": "Go", "db": "postgres"},
        Validity:  schema.Validity{Mode: schema.ValidityModeGlobal},
        Evidence: []schema.ProvenanceRef{
            {SourceType: "observation", SourceID: "obs-003", Timestamp: time.Now()},
        },
    },
}

result, err := m.Merge(ctx, []string{id1, id2}, merged, "consolidator", "consolidated preference records")

Contest

func (s *Service) Contest(
    ctx           context.Context,
    id            string,
    contestingRef string,
    actor         string,
    rationale     string,
) error
Marks a record as contested, indicating conflicting evidence exists. For semantic records, Payload.Revision.Status is set to contested. A contested_by relation is added pointing to contestingRef.
id
string
required
ID of the record to contest.
contestingRef
string
required
ID of the conflicting record or evidence reference.
actor
string
required
Identity of the actor raising the contest.
rationale
string
required
Human-readable explanation recorded in the audit log.
err := m.Contest(
    ctx,
    originalRec.ID,
    conflictingRec.ID,
    "agent-core",
    "conflicting observation recorded by different source",
)

Decay: Reinforce and Penalize

These methods are exposed on the top-level Membrane facade and delegate to pkg/decay.Service.

Reinforce

func (m *Membrane) Reinforce(
    ctx       context.Context,
    id        string,
    actor     string,
    rationale string,
) error
Boosts Salience by DecayProfile.ReinforcementGain, capped at 1.0. Updates Lifecycle.LastReinforcedAt to reset the decay clock.
id
string
required
ID of the record to reinforce.
actor
string
required
Identity of the actor.
rationale
string
required
Explanation recorded in the audit log.
// Called when a retrieved record was used successfully
err := m.Reinforce(ctx, rec.ID, "agent-core", "plan was applied successfully")

Penalize

func (m *Membrane) Penalize(
    ctx       context.Context,
    id        string,
    amount    float64,
    actor     string,
    rationale string,
) error
Reduces Salience by amount, floored at DecayProfile.MinSalience.
id
string
required
ID of the record to penalise.
amount
float64
required
Amount to subtract from the record’s current salience.
actor
string
required
Identity of the actor.
rationale
string
required
Explanation recorded in the audit log.
// Called when a competence record led to a failed outcome
err := m.Penalize(ctx, competenceRec.ID, 0.2, "agent-core", "plan failed during execution")

Errors

SymbolDescription
ErrEpisodicImmutableReturned when any revision operation is attempted on an episodic record.
ErrRecordNotFoundAlias for storage.ErrNotFound. Returned when a referenced record does not exist.

Build docs developers (and LLMs) love