Add lifecycle registration and revisions with atomic packet uploads
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a10780-6d41-7952-9718-dfbc1f41236f
This commit is contained in:
parent
7ce1e589f7
commit
ee472acc87
10 changed files with 332 additions and 35 deletions
|
|
@ -101,11 +101,15 @@ class LifecycleRepository:
|
|||
db.execute("INSERT INTO lifecycle_operations VALUES (?,?,?,?,?,?)", (*scope, digest, event_id))
|
||||
return event_id
|
||||
|
||||
def register(self, context: Attribution, memo: Memo, *, key: str, guard=None) -> str:
|
||||
def register(self, context: Attribution, memo: Memo, *, key: str, guard=None, documents=None) -> str:
|
||||
"""Register a complete, unbound version-one memo without creating approval."""
|
||||
if memo.version != 1 or memo.sealed or memo.approval_id is not None:
|
||||
raise ValueError("registration requires an unbound version-one memo")
|
||||
scope, digest = self._request(context, "register", key, memo)
|
||||
from .lifecycle_commands import decode_documents
|
||||
documents = [] if documents is None else documents
|
||||
decoded = decode_documents(documents, memo)
|
||||
payload = {"memo": memo, "documents": documents} if documents else memo
|
||||
scope, digest = self._request(context, "register", key, payload)
|
||||
with self.store._transaction() as db:
|
||||
policy_id = guard(db) if guard is not None else None
|
||||
replay = self._replay(db, scope, digest)
|
||||
|
|
@ -114,12 +118,16 @@ class LifecycleRepository:
|
|||
# Never take over an existing intake/imported memo, even with identical content.
|
||||
if db.execute("SELECT 1 FROM memos WHERE id=?", (memo.id,)).fetchone():
|
||||
raise Conflict("memo identifier already exists")
|
||||
if {item.hash for item in memo.packet} - {item[0] for item in decoded}:
|
||||
raise EvidenceUnavailable("registration requires packet content in the command")
|
||||
for document in decoded:
|
||||
self.store._put_document(db, *document)
|
||||
self.store._save_memo(db, memo)
|
||||
db.execute("INSERT INTO lifecycle_records VALUES (?,?,?)", (memo.id, context.tenant, _now()))
|
||||
return self._append(db, scope, digest, memo, "registered", {"memo_version": memo.version}, policy_id)
|
||||
|
||||
def revise(self, context: Attribution, memo: Memo, *, expected_version: int,
|
||||
summary: str, key: str, guard=None) -> str:
|
||||
summary: str, key: str, guard=None, documents=None) -> str:
|
||||
"""Compare-and-append; retain existing Store guards on outstanding entries."""
|
||||
if type(expected_version) is not int or expected_version < 1:
|
||||
raise ValueError("expected version must be a positive integer")
|
||||
|
|
@ -127,8 +135,13 @@ class LifecycleRepository:
|
|||
raise ValueError("revision summary required, at most 4096 characters")
|
||||
if memo.version != expected_version + 1 or memo.sealed or memo.approval_id is not None:
|
||||
raise ValueError("revision requires the next unbound memo version")
|
||||
scope, digest = self._request(context, "revise", key,
|
||||
{"memo": memo, "expected_version": expected_version, "summary": summary})
|
||||
from .lifecycle_commands import decode_documents
|
||||
documents = [] if documents is None else documents
|
||||
decoded = decode_documents(documents, memo)
|
||||
payload = {"memo": memo, "expected_version": expected_version, "summary": summary}
|
||||
if documents:
|
||||
payload["documents"] = documents
|
||||
scope, digest = self._request(context, "revise", key, payload)
|
||||
with self.store._transaction() as db:
|
||||
policy_id = guard(db) if guard is not None else None
|
||||
self._record(db, context.tenant, memo.id)
|
||||
|
|
@ -140,6 +153,11 @@ class LifecycleRepository:
|
|||
raise Conflict("memo changed since it was retrieved")
|
||||
if current.sealed or current.approval_id is not None:
|
||||
raise Conflict("bound memo requires the review integration path")
|
||||
available = {item.hash for item in current.packet} | {item[0] for item in decoded}
|
||||
if {item.hash for item in memo.packet} - available:
|
||||
raise EvidenceUnavailable("revision requires new packet content in the command")
|
||||
for document in decoded:
|
||||
self.store._put_document(db, *document)
|
||||
self.store._save_memo(db, memo)
|
||||
return self._append(db, scope, digest, memo, "revised", {"summary": summary}, policy_id)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue