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.