Persist review evidence and deliver audit records transactionally

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
This commit is contained in:
tegwick 2026-09-10 23:27:19 +02:00
parent 0e48355b9f
commit 2cc32168ac
14 changed files with 1474 additions and 22 deletions

View file

@ -0,0 +1,48 @@
"""JSON persistence of the existing domain objects; never pickle or a new memo schema."""
from dataclasses import asdict
import json
from .disposition import Actor, ActorKind, Disposition, Verb
from .memo import (BindingLevel, BindingSlice, Highlight, Identifier, Memo,
PacketItem, Principal, Scope, StepKind)
from .presentation import Phase, Presentation
from .provenance import Claim, Route
def dumps(value) -> str:
return json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False,
allow_nan=False, default=lambda x: sorted(x) if isinstance(x, frozenset) else asdict(x))
def memo_from(data: dict) -> Memo:
data = dict(data)
binding = dict(data["binding"])
principal = dict(binding["principal"])
principal["identifiers"] = tuple(Identifier(**i) for i in principal.get("identifiers", []))
binding["principal"] = Principal(**principal)
binding["target"] = Scope(**binding["target"])
data["binding"] = BindingSlice(**binding)
data["binding_level"] = BindingLevel(data["binding_level"])
data["step_kind"] = StepKind(data["step_kind"])
data["packet"] = tuple(PacketItem(**p) for p in data["packet"])
data["highlights"] = tuple(Highlight(**h) for h in data["highlights"])
return Memo(**data)
def presentation_from(data: dict) -> Presentation:
data = dict(data)
data["phase"] = Phase(data["phase"])
data["acked_highlight_ids"] = frozenset(data["acked_highlight_ids"])
for field in ("tenant", "principal_type"):
if data[field] is not None:
data[field] = Claim(data[field]["value"], Route(data[field]["route"]))
return Presentation(**data)
def disposition_from(data: dict) -> Disposition:
data = dict(data)
data["verb"] = Verb(data["verb"])
data["actor"] = Actor(data["actor"]["sub"], ActorKind(data["actor"]["kind"]))
data["reasons"] = tuple(data["reasons"])
return Disposition(**data)