Add protected headless lifecycle application service
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a10780-6d41-7952-9718-dfbc1f41236f
This commit is contained in:
parent
f7094f8313
commit
b2a4b863a8
7 changed files with 439 additions and 12 deletions
|
|
@ -90,8 +90,10 @@ class LifecycleRepository:
|
|||
return None
|
||||
|
||||
@staticmethod
|
||||
def _append(db, scope, digest, memo, kind, body):
|
||||
def _append(db, scope, digest, memo, kind, body, policy_id=None):
|
||||
event_id = str(uuid.uuid4())
|
||||
if policy_id is not None:
|
||||
body = {**body, "policy_observation_id": policy_id}
|
||||
db.execute("INSERT INTO lifecycle_events "
|
||||
"(id,tenant,memo_id,version,kind,actor,at,body) VALUES (?,?,?,?,?,?,?,?)",
|
||||
(event_id, scope[0], memo.id, memo.version, kind, scope[1], _now(), dumps(body)))
|
||||
|
|
@ -99,12 +101,13 @@ 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) -> str:
|
||||
def register(self, context: Attribution, memo: Memo, *, key: str, guard=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)
|
||||
with self.store._transaction() as db:
|
||||
policy_id = guard(db) if guard is not None else None
|
||||
replay = self._replay(db, scope, digest)
|
||||
if replay:
|
||||
return replay
|
||||
|
|
@ -113,10 +116,10 @@ class LifecycleRepository:
|
|||
raise Conflict("memo identifier already exists")
|
||||
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})
|
||||
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) -> str:
|
||||
summary: str, key: str, guard=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,6 +130,7 @@ class LifecycleRepository:
|
|||
scope, digest = self._request(context, "revise", key,
|
||||
{"memo": memo, "expected_version": expected_version, "summary": summary})
|
||||
with self.store._transaction() as db:
|
||||
policy_id = guard(db) if guard is not None else None
|
||||
self._record(db, context.tenant, memo.id)
|
||||
replay = self._replay(db, scope, digest)
|
||||
if replay:
|
||||
|
|
@ -137,10 +141,10 @@ class LifecycleRepository:
|
|||
if current.sealed or current.approval_id is not None:
|
||||
raise Conflict("bound memo requires the review integration path")
|
||||
self.store._save_memo(db, memo)
|
||||
return self._append(db, scope, digest, memo, "revised", {"summary": summary})
|
||||
return self._append(db, scope, digest, memo, "revised", {"summary": summary}, policy_id)
|
||||
|
||||
def annotate(self, context: Attribution, memo_id: str, version: int, *, kind: str,
|
||||
body: dict, key: str) -> str:
|
||||
body: dict, key: str, guard=None) -> str:
|
||||
"""Append a source, advisory evaluation or discussion; never a disposition."""
|
||||
self._validate_annotation(kind, body)
|
||||
if type(version) is not int or version < 1:
|
||||
|
|
@ -148,6 +152,7 @@ class LifecycleRepository:
|
|||
scope, digest = self._request(context, kind, key,
|
||||
{"memo_id": memo_id, "version": version, "body": body})
|
||||
with self.store._transaction() as db:
|
||||
policy_id = guard(db) if guard is not None else None
|
||||
self._record(db, context.tenant, memo_id)
|
||||
replay = self._replay(db, scope, digest)
|
||||
if replay:
|
||||
|
|
@ -159,7 +164,7 @@ class LifecycleRepository:
|
|||
"AND memo_id=? AND version=? AND kind='source'",
|
||||
(source, context.tenant, memo_id, version)).fetchone():
|
||||
raise EvidenceUnavailable("evaluation source unavailable for this revision")
|
||||
return self._append(db, scope, digest, memo, kind, body)
|
||||
return self._append(db, scope, digest, memo, kind, body, policy_id)
|
||||
|
||||
@staticmethod
|
||||
def _validate_annotation(kind, body):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue