Align lifecycle persistence with review isolation and runtime health
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a10780-6d41-7952-9718-dfbc1f41236f
This commit is contained in:
parent
b2a4b863a8
commit
f0e9341650
8 changed files with 102 additions and 5 deletions
|
|
@ -123,5 +123,6 @@ def admin():
|
|||
else:
|
||||
with store._connection() as db:
|
||||
print(json.dumps({'schema_version': db.execute('PRAGMA user_version').fetchone()[0],
|
||||
'lifecycle': store.lifecycle_counts(),
|
||||
'outbox': {r[0]: r[1] for r in db.execute('SELECT state,COUNT(*) FROM outbox GROUP BY state')},
|
||||
'submissions': {r[0]: r[1] for r in db.execute('SELECT state,COUNT(*) FROM submissions GROUP BY state')}}))
|
||||
|
|
|
|||
|
|
@ -47,7 +47,11 @@ class AuditPump:
|
|||
|
||||
def ready(self):
|
||||
with self._lock:
|
||||
return self._last_ok is not None and self.clock() - self._last_ok < 90
|
||||
recent = self._last_ok is not None and self.clock() - self._last_ok < 90
|
||||
try:
|
||||
return recent and self.store.lifecycle_counts()["pending"] == 0
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def tick(self):
|
||||
try:
|
||||
|
|
@ -78,6 +82,8 @@ class AuditPump:
|
|||
row["state"] != "delivered" for row in self.store.outbox())
|
||||
if self.intake_worker and self.store.intake_audit_pending():
|
||||
healthy = False
|
||||
if self.store.lifecycle_counts()["pending"]:
|
||||
healthy = False
|
||||
with self._lock:
|
||||
self._last_ok = now if healthy else None
|
||||
except Exception:
|
||||
|
|
|
|||
|
|
@ -168,6 +168,8 @@ class Store:
|
|||
|
||||
def save_memo(self, memo: Memo):
|
||||
with self._transaction() as db:
|
||||
if db.execute("SELECT 1 FROM lifecycle_records WHERE memo_id=?", (memo.id,)).fetchone():
|
||||
raise Conflict("registered lifecycle memos require lifecycle revision commands")
|
||||
self._save_memo(db, memo)
|
||||
|
||||
def _save_memo(self, db, memo: Memo):
|
||||
|
|
@ -421,13 +423,23 @@ class Store:
|
|||
"SELECT body FROM dispositions WHERE presentation_id=? ORDER BY rowid", (presentation_id,))]
|
||||
|
||||
def memos_for(self, subject):
|
||||
"""Latest version of every held memo naming ``subject`` as the person bound."""
|
||||
"""Legacy review candidates; unpublished lifecycle records stay private."""
|
||||
with self._connection() as db:
|
||||
rows = db.execute("SELECT m.body FROM memos m WHERE m.version="
|
||||
"(SELECT MAX(version) FROM memos WHERE id=m.id) ORDER BY m.id").fetchall()
|
||||
"(SELECT MAX(version) FROM memos WHERE id=m.id) "
|
||||
"AND NOT EXISTS (SELECT 1 FROM lifecycle_records l WHERE l.memo_id=m.id) "
|
||||
"ORDER BY m.id").fetchall()
|
||||
memos = (memo_from(json.loads(r[0])) for r in rows)
|
||||
return [m for m in memos if m.binding.principal.id == subject and m.binding.principal.kind == "person"]
|
||||
|
||||
def lifecycle_counts(self):
|
||||
"""Content-free operational counts, including undelivered lifecycle evidence."""
|
||||
with self._connection() as db:
|
||||
return {name: db.execute(f"SELECT COUNT(*) FROM {table}").fetchone()[0]
|
||||
for name, table in (("records", "lifecycle_records"),
|
||||
("events", "lifecycle_events"),
|
||||
("pending", "lifecycle_pending"))}
|
||||
|
||||
def dispositions_by(self, subject, memo_id):
|
||||
"""``subject``'s dispositions on every version of a memo, oldest first, with any submission."""
|
||||
with self._connection() as db:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue