Skip to content

symfonic.memory.protocols_review

protocols_review

Optional durable procedural review capability, separate from GraphBackend.

ProcedureReviewBackend

Bases: Protocol

An optional backend capability; existing graph providers need not implement it.

Callers must explicitly require this capability before claiming durable review CAS. Generic update_node remains unconditional and can bypass this seam; approval routes are not durable until all review writers use CAS or the backend enforces review conditions on every write.

compare_and_set_procedure_review async

compare_and_set_procedure_review(scope: StorageScope, node_id: NodeId, expected_properties: dict[str, Any], properties: dict[str, Any]) -> Any | None

Review a draft matching a detached snapshot of get_node.properties.

The caller must deepcopy the read properties before building a proposal or awaiting other work: reference backends may return live aliases. Inputs must contain only JSON-serializable data. Every artifact property must retain its exact presence/value. Only status, active, attribution, revision and approval action_tool/precondition bindings may change. Bindings may be added/overwritten only with non-None values, never deleted. An existing unchanged None binding can remain unchanged; ownership is restored from the committed row. Actor authentication and authorization remain the caller's policy, not this persistence seam. Compare every projected property, including presence, status and review revision. PostgreSQL's reserved model counter is preserved separately. Return None for a changed snapshot or non-draft; raise KeyError for a missing/not-exactly-owned row and ValueError for malformed data/non-procedural rows. Ancestor read visibility does not confer review ownership. Legacy absent/NULL owners belong only to the legacy tenant root; native scopes cannot infer ownership from them. Ownership remains immutable; revision advances exactly once (missing means zero). Recognized authority and nonblank actor are attribution data, not authorization. Only draft to approved/active or rejected/inactive is accepted. No unconditional writer is intercepted.

Source code in src/symfonic/memory/protocols_review.py
async def compare_and_set_procedure_review(
    self, scope: StorageScope, node_id: NodeId,
    expected_properties: dict[str, Any], properties: dict[str, Any],
) -> Any | None:
    """Review a draft matching a detached snapshot of get_node.properties.

    The caller must deepcopy the read properties before building a proposal
    or awaiting other work: reference backends may return live aliases.
    Inputs must contain only JSON-serializable data. Every artifact property
    must retain its exact presence/value. Only status, active, attribution,
    revision and approval action_tool/precondition bindings may change.
    Bindings may be added/overwritten only with non-None values, never
    deleted. An existing unchanged None binding can remain unchanged;
    ownership is restored from the committed row. Actor authentication and
    authorization remain the caller's policy, not this persistence seam.
    Compare every projected property, including presence, status and review
    revision. PostgreSQL's reserved model counter is preserved separately.
    Return None for a changed snapshot or non-draft; raise KeyError for a
    missing/not-exactly-owned row and ValueError for malformed data/non-procedural
    rows. Ancestor read visibility does not confer review ownership. Legacy
    absent/NULL owners belong only to the legacy tenant root; native scopes
    cannot infer ownership from them. Ownership remains immutable; revision advances exactly
    once (missing means zero). Recognized authority and nonblank actor are
    attribution data, not authorization. Only draft to approved/active or
    rejected/inactive is accepted. No unconditional writer is intercepted.
    """
    ...