fix(execution): retain scoped cleanup after uncertain outcomes

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
This commit is contained in:
codex 2026-10-16 01:51:53 +02:00
parent 3b6e647aa0
commit 59d1441cf8
7 changed files with 462 additions and 4 deletions

View file

@ -57,6 +57,26 @@ _NEXT = {
}
@dataclass(frozen=True)
class Cleanup:
"""Owner-derived exact call commitment, never a handle or authority token.
The owner mediator must include these commitments in its approved plan before
reservation, then compare the actual native cleanup call immediately before
dispatch. This journal does not authenticate that plan or native adapter.
"""
kind: str
call_digest: str
def validate(self):
if type(self.kind) is not str or self.kind not in {
"task-token-revoke", "identity-token-revoke", "grant-policy-delete"
}:
raise Refused("unsupported cleanup obligation")
if type(self.call_digest) is not str or not re.fullmatch(r"[0-9a-f]{64}", self.call_digest):
raise Refused("invalid cleanup call digest")
class Journal:
def __init__(self, directory: Path):
# Require an existing owner-private directory: deployment creates it.
@ -82,8 +102,10 @@ class Journal:
self.db.execute("PRAGMA journal_mode=DELETE")
self.db.execute("CREATE TABLE IF NOT EXISTS operations (approval TEXT PRIMARY KEY, request TEXT NOT NULL, operation TEXT UNIQUE NOT NULL, plan TEXT NOT NULL, state TEXT NOT NULL, evidence TEXT)")
self.db.execute("CREATE TABLE IF NOT EXISTS calls (operation TEXT NOT NULL, ordinal INTEGER NOT NULL, call_digest TEXT NOT NULL, outcome TEXT NOT NULL, evidence TEXT, PRIMARY KEY(operation,ordinal))")
self.db.execute("CREATE TABLE IF NOT EXISTS cleanup (operation TEXT NOT NULL, ordinal INTEGER NOT NULL, kind TEXT NOT NULL, call_digest TEXT NOT NULL, outcome TEXT NOT NULL, evidence TEXT, PRIMARY KEY(operation,ordinal), UNIQUE(operation,kind))")
self._held = False
self._admission = None
self._consumed_admission = None
self._sync_directory()
@staticmethod
@ -123,11 +145,20 @@ class Journal:
yield self
finally:
self._admission = None
self._consumed_admission = None
self._held = False
fcntl.flock(self._lock_fd, fcntl.LOCK_UN)
def reserve(self, binding: Binding):
def reserve(self, binding: Binding, cleanup: tuple[Cleanup, ...] = ()):
binding.validate()
if type(cleanup) is not tuple or len(cleanup) > 3:
raise Refused("closed cleanup plan required")
for item in cleanup:
if type(item) is not Cleanup:
raise Refused("typed cleanup obligation required")
item.validate()
if len({item.kind for item in cleanup}) != len(cleanup):
raise Refused("duplicate cleanup obligation")
if not self._held or self._admission is not None:
raise Refused("reservation requires fresh exclusive invocation")
try:
@ -135,6 +166,9 @@ class Journal:
self.db.execute("INSERT INTO operations VALUES (?,?,?,?,?,NULL)",
(binding.approval_id, binding.request_digest,
binding.operation_id, binding.plan_digest, "reserved"))
self.db.executemany("INSERT INTO cleanup VALUES (?,?,?,?,'owed',NULL)",
[(binding.operation_id, i, item.kind, item.call_digest)
for i, item in enumerate(cleanup)])
self.db.execute("COMMIT")
self._sync_directory()
except sqlite3.IntegrityError:
@ -158,6 +192,13 @@ class Journal:
try:
self.db.execute("BEGIN IMMEDIATE")
pending=self.db.execute("SELECT COUNT(*) FROM calls WHERE operation=? AND outcome='pending'",(binding.operation_id,)).fetchone()[0]
started = self.db.execute("SELECT COUNT(*) FROM cleanup WHERE operation=? AND outcome!='owed'", (binding.operation_id,)).fetchone()[0]
if started and target not in {'unknown', 'cleanup-confirmed'}:
raise Refused("cleanup has closed business execution")
if target == 'cleanup-confirmed':
total, owed = self.db.execute("SELECT COUNT(*),COALESCE(SUM(outcome!='confirmed'),0) FROM cleanup WHERE operation=?", (binding.operation_id,)).fetchone()
if not total or owed:
raise Refused("explicit cleanup obligations are unconfirmed")
if pending and target != 'unknown':
raise Refused("unconfirmed external call requires unknown")
changed = self.db.execute(
@ -168,6 +209,8 @@ class Journal:
raise Refused("journal state changed")
self.db.execute("COMMIT")
self._sync_directory()
if target == "consume-confirmed":
self._consumed_admission = binding
except BaseException:
if self.db.in_transaction:
self.db.execute("ROLLBACK")
@ -182,6 +225,7 @@ class Journal:
raise Refused("journal binding mismatch")
# Readback cannot create a live admission, even for an interrupted state.
pending = self.db.execute("SELECT COUNT(*) FROM calls WHERE operation=? AND outcome='pending'", (binding.operation_id,)).fetchone()[0]
pending += self.db.execute("SELECT COUNT(*) FROM cleanup WHERE operation=? AND outcome='pending'", (binding.operation_id,)).fetchone()[0]
return {"state": row[3], "evidence_digest": row[4], "dispatch_allowed": False,
"external_outcome_unknown": bool(pending)}
@ -201,7 +245,8 @@ class Journal:
self.db.execute("BEGIN IMMEDIATE")
count,pending = self.db.execute("SELECT COUNT(*), COALESCE(SUM(outcome='pending'),0) FROM calls WHERE operation=?",(binding.operation_id,)).fetchone()
state=self.db.execute("SELECT state FROM operations WHERE operation=?",(binding.operation_id,)).fetchone()[0]
if ordinal != count or pending or state in {'failed','unknown','cleanup-confirmed'}:
cleanup_started = self.db.execute("SELECT COUNT(*) FROM cleanup WHERE operation=? AND outcome!='owed'", (binding.operation_id,)).fetchone()[0]
if cleanup_started or ordinal != count or pending or state in {'failed','unknown','cleanup-confirmed'}:
raise Refused("call is replayed, uncertain or terminal")
self.db.execute("INSERT INTO calls VALUES (?,?,?,'pending',NULL)",(binding.operation_id,ordinal,call_digest))
self.db.execute("COMMIT")
@ -229,6 +274,61 @@ class Journal:
if self.db.in_transaction: self.db.execute("ROLLBACK")
raise
def cleanup_status(self, binding: Binding):
# Observation never restores live execution or cleanup authority.
if self.observe(binding) is None:
raise Refused("operation is not admitted")
rows = self.db.execute("SELECT ordinal,kind,call_digest,outcome,evidence FROM cleanup WHERE operation=? ORDER BY ordinal", (binding.operation_id,)).fetchall()
return {"confirmed": bool(rows) and all(row[3] == "confirmed" for row in rows),
"obligations": [{"ordinal": row[0], "kind": row[1], "call_digest": row[2],
"outcome": row[3], "evidence_digest": row[4]} for row in rows]}
def _cleanup_admission(self, binding, ordinal, obligation):
if not self._held or self._admission != binding or self._consumed_admission != binding:
raise Refused("cleanup requires same live consumed admission")
if type(ordinal) is not int or not 0 <= ordinal < 3 or type(obligation) is not Cleanup:
raise Refused("exact cleanup obligation required")
obligation.validate()
def before_cleanup(self, binding: Binding, ordinal: int, obligation: Cleanup):
"""Commit intent for one pre-admitted cleanup call, even after unknown.
Never resumes an interrupted invocation. Independent owner recovery after
a crash still requires the owner's protected recovery channel/approval.
Cleanup has no business deadline: its authority is the original separate
explicit obligation, and cannot authorize a read, repair or business write.
"""
self._cleanup_admission(binding, ordinal, obligation)
try:
self.db.execute("BEGIN IMMEDIATE")
changed = self.db.execute("UPDATE cleanup SET outcome='pending' WHERE operation=? AND ordinal=? AND kind=? AND call_digest=? AND outcome='owed'",
(binding.operation_id, ordinal, obligation.kind, obligation.call_digest)).rowcount
if changed != 1:
raise Refused("cleanup is unadmitted, replayed or uncertain")
self.db.execute("COMMIT")
self._sync_directory()
except BaseException:
if self.db.in_transaction: self.db.execute("ROLLBACK")
raise
def after_cleanup(self, binding: Binding, ordinal: int, obligation: Cleanup,
*, confirmed: bool, evidence_digest: str):
self._cleanup_admission(binding, ordinal, obligation)
if type(confirmed) is not bool or type(evidence_digest) is not str or not re.fullmatch(r"[0-9a-f]{64}", evidence_digest):
raise Refused("closed cleanup evidence required")
try:
self.db.execute("BEGIN IMMEDIATE")
changed = self.db.execute("UPDATE cleanup SET outcome=?, evidence=? WHERE operation=? AND ordinal=? AND kind=? AND call_digest=? AND outcome='pending'",
('confirmed' if confirmed else 'unconfirmed', evidence_digest,
binding.operation_id, ordinal, obligation.kind, obligation.call_digest)).rowcount
if changed != 1:
raise Refused("cleanup confirmation mismatch")
self.db.execute("COMMIT")
self._sync_directory()
except BaseException:
if self.db.in_transaction: self.db.execute("ROLLBACK")
raise
def close(self):
if hasattr(self, "db"):
self.db.close()