Skip to content

symfonic.memory.backends.postgres_retirement_evidence

postgres_retirement_evidence

Read-only terminal evidence for a future separate chat completer (CORE-428).

This is not a RetirementWitness: it holds no witness key and grants no chat deletion authority. A distinct signer must bind it to the chat intent and database, and a restricted chat-DB principal must verify that signature.

prove_terminal async

prove_terminal(eraser: Any, tenant_id: str, job_id: str, *, runtime_login: str, binding: Any) -> TerminalRetirementEvidence

Recheck one exact, versioned, empty tenant-root retirement under its fence.

Do not call retire_tenant here: a proof request must never initiate an irreversible retirement. This is a read-side prerequisite, not an issuer.

Source code in src/symfonic/memory/backends/postgres_retirement_evidence.py
async def prove_terminal(
    eraser: Any, tenant_id: str, job_id: str, *, runtime_login: str, binding: Any
) -> TerminalRetirementEvidence:
    """Recheck one exact, versioned, empty tenant-root retirement under its fence.

    Do not call ``retire_tenant`` here: a proof request must never initiate an
    irreversible retirement. This is a read-side prerequisite, not an issuer.
    """
    from symfonic.capabilities.memory.scope import MemoryScope
    from symfonic.memory.backends.postgres_erase_content import content_ready
    from symfonic.memory.backends.postgres_erase_retirement import installed, require_empty
    from symfonic.memory.backends.postgres_native_eraser import PostgresNativeEraser
    from symfonic.memory.backends.postgres_retirement_receipt import initiation, verify
    from symfonic.memory.storage_scope import NativeStorageScope

    if (
        type(eraser) is not PostgresNativeEraser
        or type(tenant_id) is not str
        or not tenant_id
        or type(job_id) is not str
        or not job_id
    ):
        raise MemoryContractError(INVALID)
    root = NativeStorageScope.from_scope(MemoryScope.from_levels((("tenant", tenant_id),)))
    await eraser._verified()
    async with eraser._transaction(binding) as conn:
        jobs = await eraser._jobs(conn, runtime_login)
        if not await installed(conn, jobs) or not await content_ready(conn, jobs):
            raise MemoryContractError(INVALID)
        if eraser._receipt_keys is None:
            raise MemoryContractError(INVALID)
        await initiation(conn, jobs, eraser)
        row = await conn.fetchrow(
            f"SELECT tenant_id, prefix, receipt_key_id, receipt_binding, receipt_anchor "
            f"FROM {jobs} WHERE id=$1 AND tenant_id=$2 AND permanent "
            "AND state='retired' FOR SHARE",
            job_id,
            tenant_id,
        )
        if row is None or row["prefix"] != root.subtree_prefix or not row["receipt_key_id"]:
            raise MemoryContractError(INVALID)
        await require_empty(conn, jobs, job_id)
        receipts = jobs.rsplit(".", 1)[0] + ".memory_erase_receipts"
        await verify(conn, jobs, receipts, job_id, eraser)
        anchor_head = await eraser.proof.verify(conn, pinned=True)
        return TerminalRetirementEvidence(
            tenant_id,
            job_id,
            row["receipt_binding"],
            row["receipt_anchor"],
            row["receipt_key_id"],
            anchor_head,
        )