Skip to content

symfonic.memory.backends.postgres_erase_incarnation

postgres_erase_incarnation

Every memory connection checkout proves the anchored lineage first (CORE-171).

PostgresPoolManager.acquire runs this guard on every connection it hands out, before any caller sees it: graph and HMS reads, direct store reads, admin services, eraser workers, fresh turns and conversation history composed with them all acquire from guarded pools. Nothing is cached: an already-open connection to a fork, or to a copy the anchor has since moved past (another lineage acknowledged a forget), refuses at its next checkout, not when the pool recycles it. A connection a caller's transaction already holds is the one checked when that transaction began.

Each check is one anchor read and one local log lookup, bounded by timeout; a timeout or transport error admits nothing. The anchor's own pool never carries this guard, so verification cannot recurse into itself.

ConnectionGuard

ConnectionGuard(proof: Any, *, timeout: float = VERIFY_SECONDS, pinned: bool = False)

Hand out a memory connection only once the anchor lineage verifies on it.

Source code in src/symfonic/memory/backends/postgres_erase_incarnation.py
def __init__(
    self, proof: Any, *, timeout: float = VERIFY_SECONDS, pinned: bool = False
) -> None:
    self._proof = proof
    self._timeout = timeout
    self._pinned = pinned  # the eraser's own pool: proven in its pinned schema

EraseAnchorRequired

Bases: MemoryContractError

A 11.2.x eraser composition upgraded to 11.3.0 without its anchor.

anchored

anchored(pool: Any, anchor: Any, schema: str, key: bytes) -> tuple[Any, ConnectionGuard]

The eraser's proof and the guard for the pools it serves, or refuse.

The eraser's own pool is proven pinned to schema, as every eraser transaction runs; a serving pool (guarding) is proven on its own resolution. When the two coincide, both guards run on that pool.

Source code in src/symfonic/memory/backends/postgres_erase_incarnation.py
def anchored(pool: Any, anchor: Any, schema: str, key: bytes) -> tuple[Any, ConnectionGuard]:
    """The eraser's proof and the guard for the pools it serves, or refuse.

    The eraser's own pool is proven pinned to ``schema``, as every eraser
    transaction runs; a serving pool (``guarding``) is proven on its own
    resolution. When the two coincide, both guards run on that pool.
    """
    from symfonic.memory.backends.postgres_erase_anchor import EraseProof

    if anchor is None:
        raise EraseAnchorRequired(REQUIRED)
    proof = EraseProof(anchor, schema=schema, receipt_key=key)
    proof.own_pool = pool
    install(pool, ConnectionGuard(proof, pinned=True))
    return proof, ConnectionGuard(proof)

anchored_graph

anchored_graph(pool: Any, eraser: Any) -> Any

Guard pool with an exact eraser's proof; any other composition refuses native reads.

Source code in src/symfonic/memory/backends/postgres_erase_incarnation.py
def anchored_graph(pool: Any, eraser: Any) -> Any:
    """Guard ``pool`` with an exact eraser's proof; any other composition refuses native reads."""
    from symfonic.memory.backends.postgres_native_eraser import PostgresNativeEraser

    if type(eraser) is PostgresNativeEraser:
        return eraser.guarding(pool)
    pool.guard_connections(_UNANCHORED)
    return eraser

graph_eraser

graph_eraser(pool: Any, eraser: Any) -> Any

The graph's eraser once pool is guarded: any PostgresPoolManager, subclasses too.

Another pool is outside the graph's contract: it cannot prove an anchored eraser's checkouts, so that composition refuses; others stay as composed.

Source code in src/symfonic/memory/backends/postgres_erase_incarnation.py
def graph_eraser(pool: Any, eraser: Any) -> Any:
    """The graph's eraser once ``pool`` is guarded: any PostgresPoolManager, subclasses too.

    Another pool is outside the graph's contract: it cannot prove an anchored
    eraser's checkouts, so that composition refuses; others stay as composed.
    """
    from symfonic.memory.backends.pool import PostgresPoolManager
    from symfonic.memory.backends.postgres_native_eraser import PostgresNativeEraser

    if isinstance(pool, PostgresPoolManager):
        return pool.anchor_graph(eraser)
    if type(eraser) is PostgresNativeEraser:
        raise EraseAnchorRequired(UNGUARDABLE)
    return eraser

install

install(pool: Any, guard: ConnectionGuard) -> None

Attach guard to pool; refuse the anchor's own pool.

Source code in src/symfonic/memory/backends/postgres_erase_incarnation.py
def install(pool: Any, guard: ConnectionGuard) -> None:
    """Attach ``guard`` to ``pool``; refuse the anchor's own pool."""
    if pool is guard.anchor_pool:
        raise MemoryContractError(RECURSIVE)
    pool.guard_connections(guard)