"""Fail-closed signed deterministic execution amendment for R7.""" from datetime import datetime, timezone import hashlib, json, sqlite3 from pathlib import Path from typing import Mapping from aios_task_terminal_recovery import DeterministicPlan, RecoveryError, canonical_json AMENDMENT_SCHEMA="aios.deterministic-execution-amendment.v1" APPLY_SCHEMA="aios.deterministic-execution-amendment-apply.v1" NAMESPACE="aios-owner-approval-v1" EVENT="TASK_RECOVERY_EXECUTION_AMENDMENT_APPLIED" APPLY_STATES=frozenset({"FAILED", "QUEUED"}) def _err(code): raise RecoveryError(code) def _sha(v): return hashlib.sha256(canonical_json(v).encode()).hexdigest() def amendment_body(x): return {k:v for k,v in x.items() if k not in {"signature","amendment_id"}} def amendment_id(x): return "sha256:"+_sha(amendment_body(x)) def signed_payload(x): return canonical_json({"amendment_id":x["amendment_id"],**amendment_body(x)}).encode() def parse_amendment(raw): x=dict(raw) required={"schema","amendment_id","nonce","task_id","job_id","generation", "repository","branch","expected_branch_oid","recovery_epoch","decision_id", "plan_id","plan_sha256","expected_apply_status","expected_apply_revision", "expected_apply_attempt","expected_current_capabilities","envelope", "owner_identity","key_id","issued_at","not_before","expires_at", "one_time_use","signature"} if set(x)=x["expires_at"]:_err("AMENDMENT_EXPIRED_OR_NOT_YET_VALID") if not self.verifier.verify(namespace=NAMESPACE,payload=signed_payload(x),signature=x["signature"],key_id=x["key_id"]):_err("AMENDMENT_SIGNATURE_INVALID") with self._db() as c: c.execute("BEGIN IMMEDIATE"); e=_validate_envelope(x["envelope"],self._plan(c,x),x) ej=canonical_json(e); ed=e["execution_digest"]; stored=dict(x); stored["signature"]="" old=c.execute("SELECT * FROM deterministic_execution_amendments WHERE amendment_id=?",(x["amendment_id"],)).fetchone() if old: if old["envelope_json"]!=ej:_err("AMENDMENT_ID_REUSE_MISMATCH") c.commit(); return {"status":"PRESENT","amendment_id":x["amendment_id"],"task_id":x["task_id"],"decision_id":x["decision_id"],"plan_id":x["plan_id"],"execution_digest":ed} if c.execute("SELECT 1 FROM deterministic_execution_amendments WHERE nonce=? OR (task_id=? AND decision_id=?)",(x["nonce"],x["task_id"],x["decision_id"])).fetchone():_err("AMENDMENT_REPLAY_OR_DECISION_REUSE") c.execute("INSERT INTO deterministic_execution_amendments VALUES(?,?,?,?,?,?,?,?,?,?)",(x["amendment_id"],x["nonce"],x["task_id"],x["decision_id"],x["plan_id"],x["plan_sha256"],ed,ej,canonical_json(stored),now)); c.commit() return {"status":"PERSISTED","amendment_id":x["amendment_id"],"task_id":x["task_id"],"decision_id":x["decision_id"],"plan_id":x["plan_id"],"execution_digest":ed} def apply(self,raw): if raw.get("schema")!=APPLY_SCHEMA:_err("AMENDMENT_APPLY_SCHEMA_INVALID") aid=raw.get("amendment_id"); tid=raw.get("task_id") with self._db() as c: c.execute("BEGIN IMMEDIATE"); a=c.execute("SELECT * FROM deterministic_execution_amendments WHERE amendment_id=? AND task_id=?",(aid,tid)).fetchone() if a is None:_err("AMENDMENT_NOT_FOUND") x=json.loads(a["payload_json"]); d=json.loads(a["envelope_json"]) t=c.execute("SELECT * FROM tasks WHERE task_id=?",(tid,)).fetchone() if t is None:_err("TASK_NOT_FOUND") m=json.loads(t["metadata_json"] or "{}"); cp=tuple(sorted(json.loads(t["required_capabilities_json"] or "[]"))); dc=tuple(sorted(d.get("capability_scope") or ())) rec=m.get("recovery"); rec=dict(rec) if isinstance(rec,Mapping) else {} old=m.get("execution") if isinstance(old,Mapping) and old.get("execution_digest")==a["envelope_digest"] and cp==dc and rec.get("execution_amendment_id")==aid: c.commit(); return {"status":"PRESENT","task_id":tid,"amendment_id":aid,"execution_digest":a["envelope_digest"],"revision":int(t["revision"]),"attempt":int(t["attempt"])} if t["status"]!=x["expected_apply_status"] or int(t["revision"])!=x["expected_apply_revision"] or int(t["attempt"])!=x["expected_apply_attempt"] or cp!=tuple(x["expected_current_capabilities"]) or t["claimed_by"] is not None or t["lease_token_hash"] is not None:_err("AMENDMENT_APPLY_TASK_CAS_MISMATCH") if t["status"]=="QUEUED" and rec.get("decision_id")!=x["decision_id"]:_err("AMENDMENT_DECISION_BINDING_MISMATCH") m["execution"]=d; m["execution_projection"]={"schema":"aios.online-agent.task-projection.v1","task_id":tid,"job_id":d.get("job_id"),"execution_digest":a["envelope_digest"]} rec["execution_amendment_id"]=aid; m["recovery"]=rec; now=self._now() q=c.execute("""UPDATE tasks SET required_capabilities_json=?,metadata_json=?,revision=revision+1,updated_at=? WHERE task_id=? AND status=? AND revision=? AND attempt=? AND claimed_by IS NULL AND lease_token_hash IS NULL""",(canonical_json(list(dc)),canonical_json(m),now,tid,x["expected_apply_status"],x["expected_apply_revision"],x["expected_apply_attempt"])) if q.rowcount!=1:_err("AMENDMENT_APPLY_TASK_CAS_FAILED") c.execute("INSERT INTO events(task_id,agent_id,event_type,payload_json,created_at) VALUES(?,?,?,?,?)",(tid,None,EVENT,canonical_json({"amendment_id":aid,"decision_id":x["decision_id"],"plan_id":x["plan_id"],"execution_digest":a["envelope_digest"],"required_capabilities":list(dc)}),now)); c.commit() return {"status":"APPLIED","task_id":tid,"amendment_id":aid,"decision_id":x["decision_id"],"plan_id":x["plan_id"],"execution_digest":a["envelope_digest"],"required_capabilities":list(dc),"revision":x["expected_apply_revision"]+1,"attempt":x["expected_apply_attempt"]}