Skip to content

How to Retract a Belief with contract

This guide shows you how to retract a belief so it leaves the current belief base, why contracting an absent belief does nothing, why contracting the world scope is forbidden, and how to see the retracted state in history.

Contraction is the AGM operation for giving up a belief. doxastica implements it the append-only way: it appends a retracted state rather than deleting anything. If the concept is new to you, read What Is AGM Belief Revision? first.

Requirements

Call contract

contract takes the scope, the belief id, and a caller-supplied source_event_id. It returns None.

from uuid import uuid7

from doxastica import BeliefFilter, InMemoryBackend, MemoryCore

core = MemoryCore(InMemoryBackend())
core.revise("mission-control", "ground-link", "online", source_event_id=uuid7())

# Retract the belief.
core.contract("mission-control", "ground-link", source_event_id=uuid7())

base = core.query_scope("mission-control", BeliefFilter())
print({b.belief_id: b.value for b in base})  # {}

After the contraction the belief is absent from the current base. Nothing was deleted: a retracted state was appended on top of the chain, and that retracted tail clears the belief from the live view.

Contracting an absent belief is a vacuity no-op

If the belief has no active current state (because it was never recorded, or was already retracted), contract does nothing at all. It writes no state and creates no scope. This is the AGM vacuity property: contracting something you do not believe leaves the store unchanged.

# The belief was never recorded — this is a silent no-op.
core.contract("mission-control", "never-existed", source_event_id=uuid7())
# No error, no write, no scope created.

You do not need to guard your calls with an existence check; a redundant contraction is safe and silent.

The world-scope guard

doxastica reserves one privileged scope, the world scope, identified by WORLD_SCOPE_ID. Contracting any belief in the world scope is forbidden and raises WorldScopeContractionError.

from doxastica import WORLD_SCOPE_ID, WorldScopeContractionError

try:
    core.contract(WORLD_SCOPE_ID, "satellite-status", source_event_id=uuid7())
except WorldScopeContractionError:
    print("World-scope contraction is not allowed.")

The guard fires before any write

The world-scope check is the first thing contract does, before it touches the backend. A forbidden contraction can never leak a partial write, even if the world scope was never created. Why the world scope is special is explained in Scopes and the World Scope.

Observe the retracted tail with include_retracted

By default query_scope returns only active beliefs, so a retracted belief is invisible. Pass include_retracted=True to surface beliefs whose current tail is retracted:

base = core.query_scope("mission-control", BeliefFilter(), include_retracted=True)
for b in base:
    print(b.belief_id, b.value, b.status.value)
# ground-link online retracted

The retracted state still carries the value it had at contraction; contract copies the prior stored value verbatim. To see the full history (the active state and the retracted state side by side) use get_revision_chain:

for state in core.get_revision_chain("ground-link"):
    print(state.value, state.status.value)
# online active
# online retracted

For finer control over status filtering, see How to Query the Current Belief Base with BeliefFilter.

Verification

Confirm the three behaviours in one pass:

core = MemoryCore(InMemoryBackend())
core.revise("mission-control", "ground-link", "online", source_event_id=uuid7())
core.contract("mission-control", "ground-link", source_event_id=uuid7())

# Gone from the active base:
print(core.query_scope("mission-control", BeliefFilter()))  # []

# But visible with include_retracted:
retracted = core.query_scope("mission-control", BeliefFilter(), include_retracted=True)
print([b.status.value for b in retracted])  # ['retracted']

# And still in full history:
print([s.status.value for s in core.get_revision_chain("ground-link")])
# ['active', 'retracted']

Troubleshooting

Problem: WorldScopeContractionError raised when you call contract.

Cause: The scope_id you passed equals WORLD_SCOPE_ID ("__world__"). Contraction is forbidden there by design.

Solution: Contract in a regular scope, or supersede the world-scope belief with a new revise instead of retracting it. See Scopes and the World Scope for the reasoning.

Problem: contract "did nothing": no error, no change.

Cause: This is the intended vacuity no-op: the belief had no active current state to retract.

Solution: Confirm the belief is actually active first with query_scope if you expected it to exist.