forget(store: Any, conversation: Any, scope: MemoryScope, journal: Any = None) -> Any
Return the store receipt after both erases succeed, or its job in progress.
A store refusal must leave the transcript untouched. A shared PostgreSQL
pool also rolls back memory if conversation erasure fails. Other domains
retain sequential behavior and offer no cross-store rollback guarantee.
A CORE-199 large erase commits on the eraser's own login, outside that
rollback, so on a shared pool it refuses as inherited and changes nothing.
Raw graph-only PostgreSQL v1 (CORE-194) admits the store's verb-gated
forget alone, or jointly with an exact PostgresConversationLog. On a
pool of its own the transcript is fenced by a durable erase intent before
memory is touched, and erased, with the intent, only once memory is.
The read-only native Mongo v1 store forgets only through journal
(CORE-171), and never with a conversation log; journal admits no
other store.
Source code in src/symfonic/capabilities/memory/admin_erase.py
| async def forget(store: Any, conversation: Any, scope: MemoryScope, journal: Any = None) -> Any:
"""Return the store receipt after both erases succeed, or its job in progress.
A store refusal must leave the transcript untouched. A shared PostgreSQL
pool also rolls back memory if conversation erasure fails. Other domains
retain sequential behavior and offer no cross-store rollback guarantee.
A CORE-199 large erase commits on the eraser's own login, outside that
rollback, so on a shared pool it refuses as inherited and changes nothing.
Raw graph-only PostgreSQL v1 (CORE-194) admits the store's verb-gated
forget alone, or jointly with an exact ``PostgresConversationLog``. On a
pool of its own the transcript is fenced by a durable erase intent before
memory is touched, and erased, with the intent, only once memory is.
The read-only native Mongo v1 store forgets only through ``journal``
(CORE-171), and never with a conversation log; ``journal`` admits no
other store.
"""
from symfonic.capabilities.memory import mongo_native_forget as native_mongo
if native_mongo.native_mongo_store(store):
if journal is None:
raise MemoryContractError(NO_JOURNAL)
if conversation is not None:
raise MemoryContractError(native_mongo.CONVERSATION)
return await native_mongo.forget_native_mongo(store, journal, scope)
if journal is not None:
raise MemoryContractError(JOURNAL_NOT_ADMITTED)
from symfonic.capabilities.memory.commit import domain_of
from symfonic.capabilities.memory.graph_native_admission import (
admit_raw_pg_mutation,
require_native_backends,
)
from symfonic.capabilities.memory.graph_receipt import MemoryOperationVerb
from symfonic.capabilities.memory.graph_store import GraphBackedHms
from symfonic.capabilities.memory.transactions import one_transaction
from symfonic.memory.backends.pool import PostgresPoolManager
admitted = isinstance(store, GraphBackedHms) and (
conversation is None or _exact_log(conversation)) and (
admit_raw_pg_mutation(scope, store, MemoryOperationVerb.FORGET))
if isinstance(store, GraphBackedHms) and scope.identity_version and not admitted:
participants = store.transaction_participants
require_native_backends(scope, participants[0],
participants[1] if len(participants) > 1 else None)
async def erase() -> Any:
from symfonic.capabilities.memory.records import ForgetInProgress
receipt = await store.forget(scope)
# CORE-199: an unfinished erase job is not a finished forget; the
# transcript goes with the resume that completes it.
if conversation is not None and not isinstance(receipt, ForgetInProgress):
await conversation.forget(scope)
return receipt
domain = domain_of(store) if conversation is not None else None
if isinstance(domain, PostgresPoolManager) and domain_of(conversation) is domain:
from symfonic.capabilities.memory.graph_forget import (
_proof,
deferred_acknowledgement,
native_subtree_deleter,
)
from symfonic.capabilities.memory.records import ForgetInProgress
deleter = native_subtree_deleter(getattr(store, "_graph", None))
with deferred_acknowledgement():
async with one_transaction(domain):
receipt = await erase()
proof = _proof(deleter)
if proof is not None and not isinstance(receipt, ForgetInProgress):
await proof.acknowledge(deleter.pool) # CORE-171: after the joint commit
return receipt
if admitted and conversation is not None:
await _fence(store._graph, conversation, scope)
return await erase()
|