| title | Revision |
|---|---|
| description | Atomic revision operations with full audit trails: supersede, fork, retract, merge, contest, reinforce, and penalize. |
Revision operations modify the lifecycle and status of existing memory records. All operations are atomic — partial revisions are never externally visible. Every operation appends to the record's audit log, preserving a complete history of changes.
For newly created supersede, fork, and merge records, operation metadata is server-owned. Membrane discards supplied audit history, derives the actor and timestamps from the authenticated operation, rebuilds semantic revision lineage, and inherits lifecycle policy from stored source records while resetting the reinforcement clock. Supplied evidence references and hashes remain attributed assertions; opaque evidence values are not probed as memory IDs. The gRPC boundary accepts at most 100 caller-supplied relations and requires every persisted relation target to exist and satisfy the server write policy before the transaction starts.
At the daemon boundary, revision and salience endpoints validate metadata before delegating to the storage layer. Required record identifiers must be non-empty; record IDs, actor names, rationales, merge source IDs, and contesting references must fit within the public string size limit; replacement records for Supersede, Fork, and Merge must satisfy the same MemoryRecord.Validate invariants as stored records; and Penalize amounts must be non-negative and finite.
Semantic records carry a revision.status field in their payload that transitions through:
| Status | Meaning |
|---|---|
active |
Record is currently valid |
contested |
Conflicting evidence exists; status unresolved |
retracted |
Record has been withdrawn; salience is 0 |
Atomically replaces an existing record with a new version. The old record's salience is set to 0 and its semantic status is set to retracted. The new record is stored with a supersedes relation pointing to the old record, and the old record receives the inverse superseded_by relation pointing to the replacement.
// Supersede a semantic record with a new version
superseded, err := m.Supersede(ctx, oldRecordID, newRec, "agent", "Go version updated")
if err != nil {
log.Fatal(err)
}
fmt.Printf("New record ID: %s\n", superseded.ID)Creates a new record derived from an existing source record. Unlike Supersede, both the source and the forked record remain active. Use Fork to create conditional variants of a fact or procedure without invalidating the original.
The forked record receives a derived_from relation pointing to the source, the source receives the inverse derived_semantic relation pointing to the fork, and an audit entry with action fork is appended to the source record. For semantic payloads, the forked record's revision.status is set to active.
// Fork a record for conditional validity (dev vs. prod)
forked, err := m.Fork(ctx, sourceID, conditionalRec, "agent", "different for dev environment")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Forked record ID: %s\n", forked.ID)Marks a record as retracted without deleting it. The record's salience is set to 0. For semantic records, the revision status is set to retracted. The record remains in the store so its audit trail is preserved.
Retracted records have salience 0 and are excluded from active retrieval results by default.
ID of the record to retract. Must not be episodic. Identifier of the agent or user performing the retraction. Human-readable reason stored in the audit entry.RetractResponse is empty. A successful call returns gRPC status OK.
// Retract a record that is no longer valid
err := m.Retract(ctx, recordID, "agent", "no longer accurate")
if err != nil {
log.Fatal(err)
}Atomically combines multiple source records into a single merged record. All source records are retracted (salience set to 0, semantic status set to retracted). The merged record receives derived_from relations for every source, each source receives a derived_semantic relation pointing to the merged record, and each source record receives an audit entry with action merge. For semantic payloads, the merged record's revision.status is set to active.
// Merge multiple records into one consolidated record
merged, err := m.Merge(
ctx,
[]string{id1, id2, id3},
mergedRec,
"agent",
"consolidating duplicates",
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Merged record ID: %s\n", merged.ID)Marks a record as contested, indicating that conflicting evidence exists. The record remains active with its salience unchanged, but its semantic revision status transitions to contested. When contesting_ref names an existing memory record that the server write policy also permits, a contested_by relation is added from the contested record to the conflicting record and the conflicting record receives the inverse contests relation. External, missing, and policy-denied references all follow the same non-relational evidence path, so the response does not disclose whether an inaccessible record ID exists.
Contested records are still returned by retrieval, but their status signals to the agent that the information should be treated with caution.
ID of the record to mark as contested. Must not be episodic. ID of the conflicting record or evidence. Graph relations are created only when this resolves to an existing write-authorized memory record. Identifier of the agent or user performing the contest. Human-readable reason stored in the audit entry.ContestResponse is empty. A successful call returns gRPC status OK.
// Contest a record when conflicting evidence appears
err := m.Contest(
ctx,
recordID,
conflictingRecordID,
"agent",
"new evidence contradicts this",
)
if err != nil {
log.Fatal(err)
}Boosts a record's salience, signalling that it was useful. This resets the decay clock and increments the audit log with an AuditActionReinforce entry. Reinforcement count is tracked in the metrics via retrieval_usefulness.
ReinforceResponse is empty. A successful call returns gRPC status OK.
// Reinforce a record after it contributed to a successful outcome
err := m.Reinforce(ctx, planRecord.ID, "planner-agent", "plan used successfully")
if err != nil {
log.Fatal(err)
}Reduces a record's salience by a specified amount. Use this to signal that a record contributed to a failed or unhelpful outcome.
ID of the record to penalize. Amount by which to reduce salience. Must be non-negative and finite. Salience will not go below 0. Identifier of the agent or user performing the penalization. Maximum 100 000 characters. Human-readable reason stored in the audit entry. Maximum 100 000 characters.PenalizeResponse is empty. A successful call returns gRPC status OK.
// Reduce salience of a record that led to a bad outcome
err := m.Penalize(ctx, recordID, 0.2, "build-agent", "procedure produced linker error")
if err != nil {
log.Fatal(err)
}