symfonic.memory.backends.postgres_staged_activation¶
postgres_staged_activation ¶
Verified, idempotent activation of one READY staged PostgreSQL v1 turn.
Activation runs the exact sealed FLUSH through the receipt-bound store, so the
receipt domain commits the FLUSH receipt, the claim-fenced graph release and
the vector writes in one transaction. It runs only after the committed-receipt
reader bound at publisher composition returns a local final receipt whose
owner scope, invocation, run and output digest equal the sealed READY. ACTIVE
returns unchanged; MISSING, STAGED and UNKNOWN refuse and are never retried; a
receipt that is absent publishes nothing; a reader that raises publishes
nothing. Only after the receipt verifies is this task's FLUSH armed, so the
receipt domain writes the postgres_staged_proof row in that same
transaction; ACTIVE needs it, and the arming is cleared however flush ends.
Content (CORE-339a). The armed proof carries the READY's sealed per-record
content digests. The receipt domain spends the FLUSH id inside the publication
transaction and proves every sealed row present and unchanged under a row lock
before any vector is written. A missing or rewritten row, or any other
rollback, leaves no receipt in any state: the turn stays READY and activation
raises, so it never reads UNKNOWN on its account. The raise is typed: a sealed
row absent or rewritten is StagedContentRefused, which a retry repeats;
any other rollback (an embedder timeout, a cancelled statement, a deadlock) is
StagedActivationRolledBack, and the same activate call is safe to
retry. A READY sealed before CORE-339a carries no content seal and refuses to
activate with StagedContentRefused.
Source (CORE-199). A staged Agent FLUSH bound to its accepted WRITE is
published under that same binding: the snapshot carries the exact WRITE the
READY sealed, a preflight refuses before the FLUSH id is spent when its
COMMITTED receipt is gone or no longer this manifest, and the publication
transaction re-reads that receipt under a share lock before any row is
touched. A source that changes after the preflight rolls the publication back
whole and raises SourceWriteRefused, which a retry repeats. A FLUSH staged
without a source (a direct journal caller, or a READY prepared before
CORE-199) publishes unbound, as before.
Trust boundary. The publisher is a trusted-host contract, not a defence
against hostile code in the publisher process: such code already holds the
store and can flush it directly. The database half of a separate publisher is
postgres_staged_roles; process and credential separation is outside both.
PostgresStagedPublisher ¶
One staged journal, its atomic store, one exact scope, one trusted reader.
Composition is the only place a reader is accepted; activate takes the
invocation id alone, so no call site can substitute a verifier.
Source code in src/symfonic/memory/backends/postgres_staged_activation.py
activate
async
¶
Publish one READY turn of the bound scope after a fresh exact read.
Source code in src/symfonic/memory/backends/postgres_staged_activation.py
StagedActivationRolledBack ¶
Bases: MemoryContractError
Activation rolled back whole for a reason other than sealed content.
The turn is READY with no FLUSH receipt in any state, no proof and no
vector, so calling activate again for the same invocation is safe.
require_atomic ¶
Graph release and vector writes must share the journal's receipt domain.
Source code in src/symfonic/memory/backends/postgres_staged_activation.py
require_receipt ¶
Every field of the host's durable receipt equals the sealed READY.