Files
aios/active-runtime/app/aios_agent_task_initial_execution_projection.py
T

1382 lines
57 KiB
Python

"""Owner-controlled CAS-bound initial execution projection for Online Agent Tasks.
This recovery primitive is intentionally narrower than a metadata patch API. It
only projects an ``agent_runtime`` envelope onto an existing, untouched, bare
Task after resolving the Task's durable governed binding through the canonical
Bridge. It never creates Tasks, Jobs, branches, claims, heartbeats, or results.
"""
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime, timezone
import hashlib
import hmac
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
import json
import os
from pathlib import Path
import re
import sqlite3
from typing import Any, Callable, Mapping
import urllib.error
import urllib.request
from aios_online_agent_execution import (
GovernedExecutionBinding,
validate_execution_envelope,
)
from aios_agent_task_projection_recovery_http import get_projection as get_canonical_projection, recover_from_json as recover_canonical_projection
TASK_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._:-]{2,179}$")
KEY_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._:-]{7,159}$")
SHA_RE = re.compile(r"^[0-9a-f]{64}$")
JOB_RE = TASK_RE
RUNTIME_CAPABILITY_RE = re.compile(r"^agent\.runtime\.(hermes|openclaw)$")
MAX_BODY = 64 * 1024
AUTHORIZATION_ID_ENV = "AIOS_AGENT_TASK_INITIAL_EXECUTION_PROJECTION_AUTHORIZATION_ID"
class InitialExecutionProjectionError(RuntimeError):
def __init__(self, code: str, status: int = 409) -> None:
super().__init__(code)
self.code = code
self.status = status
def _canonical(value: object) -> bytes:
return json.dumps(
value, sort_keys=True, separators=(",", ":"), ensure_ascii=False
).encode("utf-8")
def _sha(value: object) -> str:
return hashlib.sha256(_canonical(value)).hexdigest()
def _now() -> str:
return datetime.now(timezone.utc).isoformat()
def _require_string(
value: object,
code: str,
pattern: re.Pattern[str] | None = None,
) -> str:
if not isinstance(value, str) or not value.strip():
raise InitialExecutionProjectionError(code, 400)
result = value.strip()
if pattern is not None and pattern.fullmatch(result) is None:
raise InitialExecutionProjectionError(code, 400)
return result
def _required_authorization_id() -> str:
value = os.environ.get(AUTHORIZATION_ID_ENV, "").strip()
if not value:
raise RuntimeError("INITIAL_EXECUTION_PROJECTION_AUTHORIZATION_ID_MISSING")
if KEY_RE.fullmatch(value) is None:
raise RuntimeError("INITIAL_EXECUTION_PROJECTION_AUTHORIZATION_ID_INVALID")
return value
@dataclass(frozen=True)
class InitialExecutionProjectionRequest:
expected_status: str
expected_revision: int
expected_attempt: int
expected_metadata_sha256: str
expected_required_capabilities_sha256: str
expected_job_id: str
expected_execution_digest: str
required_capability: str
adapter: str
authorization_id: str
idempotency_key: str
reason: str
@classmethod
def from_mapping(
cls, value: Mapping[str, Any]
) -> "InitialExecutionProjectionRequest":
allowed = {
"expected_status",
"expected_revision",
"expected_attempt",
"expected_metadata_sha256",
"expected_required_capabilities_sha256",
"expected_job_id",
"expected_execution_digest",
"required_capability",
"adapter",
"authorization_id",
"idempotency_key",
"reason",
}
if set(value) != allowed:
raise InitialExecutionProjectionError(
"INITIAL_EXECUTION_PROJECTION_FIELDS_INVALID", 400
)
status = _require_string(value["expected_status"], "EXPECTED_STATUS_INVALID")
if status != "QUEUED":
raise InitialExecutionProjectionError("EXPECTED_STATUS_INVALID", 400)
revision = value["expected_revision"]
attempt = value["expected_attempt"]
if (
not isinstance(revision, int)
or isinstance(revision, bool)
or revision != 1
or not isinstance(attempt, int)
or isinstance(attempt, bool)
or attempt != 0
):
raise InitialExecutionProjectionError(
"INITIAL_EXECUTION_PROJECTION_INITIAL_STATE_REQUIRED", 400
)
metadata_sha = _require_string(
value["expected_metadata_sha256"], "METADATA_SHA256_INVALID", SHA_RE
)
capabilities_sha = _require_string(
value["expected_required_capabilities_sha256"],
"CAPABILITIES_SHA256_INVALID",
SHA_RE,
)
job_id = _require_string(value["expected_job_id"], "JOB_ID_INVALID", JOB_RE)
digest = _require_string(
value["expected_execution_digest"], "EXECUTION_DIGEST_INVALID", SHA_RE
)
capability = _require_string(
value["required_capability"], "RUNTIME_CAPABILITY_INVALID",
RUNTIME_CAPABILITY_RE,
)
adapter = _require_string(value["adapter"], "RUNTIME_ADAPTER_INVALID")
if capability != f"agent.runtime.{adapter}" or adapter not in {"hermes", "openclaw"}:
raise InitialExecutionProjectionError("RUNTIME_CAPABILITY_MISMATCH", 400)
authorization_id = _require_string(
value["authorization_id"], "AUTHORIZATION_ID_INVALID", KEY_RE
)
idempotency_key = _require_string(
value["idempotency_key"], "IDEMPOTENCY_KEY_INVALID", KEY_RE
)
reason = _require_string(value["reason"], "PROJECTION_REASON_INVALID")
if len(reason) > 512:
raise InitialExecutionProjectionError("PROJECTION_REASON_INVALID", 400)
return cls(
status,
revision,
attempt,
metadata_sha,
capabilities_sha,
job_id,
digest,
capability,
adapter,
authorization_id,
idempotency_key,
reason,
)
def public(self) -> dict[str, Any]:
return {
"expected_status": self.expected_status,
"expected_revision": self.expected_revision,
"expected_attempt": self.expected_attempt,
"expected_metadata_sha256": self.expected_metadata_sha256,
"expected_required_capabilities_sha256": self.expected_required_capabilities_sha256,
"expected_job_id": self.expected_job_id,
"expected_execution_digest": self.expected_execution_digest,
"required_capability": self.required_capability,
"adapter": self.adapter,
"authorization_id": self.authorization_id,
"idempotency_key": self.idempotency_key,
"reason": self.reason,
}
@dataclass(frozen=True)
class SourceCaptureProjectionRecoveryRequest:
"""CAS contract for the first durable runtime projection after source capture.
Some deployed Bridge versions materialize a binding by letting the generic
worker perform one read-only ``source_capture`` attempt. This request does
not relax the pristine initial-projection contract above. It authorizes a
separate, evidence-bound transition only after that attempt has been
officially verified as ``NEEDS_REWORK`` and returned to ``QUEUED``.
"""
expected_status: str
expected_revision: int
expected_attempt: int
expected_metadata_sha256: str
expected_required_capabilities_sha256: str
previous_verification_sha256: str
expected_source_capture_result_sha256: str
expected_source_capture_execution_digest: str
expected_job_id: str
expected_execution_digest: str
required_capability: str
adapter: str
authorization_id: str
idempotency_key: str
reason: str
@classmethod
def from_mapping(
cls, value: Mapping[str, Any]
) -> "SourceCaptureProjectionRecoveryRequest":
allowed = {
"expected_status",
"expected_revision",
"expected_attempt",
"expected_metadata_sha256",
"expected_required_capabilities_sha256",
"previous_verification_sha256",
"expected_source_capture_result_sha256",
"expected_source_capture_execution_digest",
"expected_job_id",
"expected_execution_digest",
"required_capability",
"adapter",
"authorization_id",
"idempotency_key",
"reason",
}
if set(value) != allowed:
raise InitialExecutionProjectionError(
"SOURCE_CAPTURE_PROJECTION_RECOVERY_FIELDS_INVALID", 400
)
status = _require_string(value["expected_status"], "EXPECTED_STATUS_INVALID")
revision = value["expected_revision"]
attempt = value["expected_attempt"]
if (
status != "QUEUED"
or not isinstance(revision, int)
or isinstance(revision, bool)
or revision < 2
or not isinstance(attempt, int)
or isinstance(attempt, bool)
or attempt < 1
):
raise InitialExecutionProjectionError(
"SOURCE_CAPTURE_PROJECTION_RECOVERY_STATE_INVALID", 400
)
digest_fields = {
"expected_metadata_sha256": "METADATA_SHA256_INVALID",
"expected_required_capabilities_sha256": "CAPABILITIES_SHA256_INVALID",
"previous_verification_sha256": "VERIFICATION_SHA256_INVALID",
"expected_source_capture_result_sha256": "SOURCE_CAPTURE_RESULT_SHA256_INVALID",
"expected_source_capture_execution_digest": "SOURCE_CAPTURE_EXECUTION_DIGEST_INVALID",
"expected_execution_digest": "EXECUTION_DIGEST_INVALID",
}
digests: dict[str, str] = {}
for name, code in digest_fields.items():
digests[name] = _require_string(value[name], code, SHA_RE)
job_id = _require_string(value["expected_job_id"], "JOB_ID_INVALID", JOB_RE)
capability = _require_string(
value["required_capability"],
"RUNTIME_CAPABILITY_INVALID",
RUNTIME_CAPABILITY_RE,
)
adapter = _require_string(value["adapter"], "RUNTIME_ADAPTER_INVALID")
if capability != f"agent.runtime.{adapter}" or adapter not in {"hermes", "openclaw"}:
raise InitialExecutionProjectionError("RUNTIME_CAPABILITY_MISMATCH", 400)
authorization_id = _require_string(
value["authorization_id"], "AUTHORIZATION_ID_INVALID", KEY_RE
)
idempotency_key = _require_string(
value["idempotency_key"], "IDEMPOTENCY_KEY_INVALID", KEY_RE
)
reason = _require_string(value["reason"], "PROJECTION_REASON_INVALID")
if len(reason) > 512:
raise InitialExecutionProjectionError("PROJECTION_REASON_INVALID", 400)
return cls(
status,
revision,
attempt,
digests["expected_metadata_sha256"],
digests["expected_required_capabilities_sha256"],
digests["previous_verification_sha256"],
digests["expected_source_capture_result_sha256"],
digests["expected_source_capture_execution_digest"],
job_id,
digests["expected_execution_digest"],
capability,
adapter,
authorization_id,
idempotency_key,
reason,
)
def public(self) -> dict[str, Any]:
return {
"expected_status": self.expected_status,
"expected_revision": self.expected_revision,
"expected_attempt": self.expected_attempt,
"expected_metadata_sha256": self.expected_metadata_sha256,
"expected_required_capabilities_sha256": self.expected_required_capabilities_sha256,
"previous_verification_sha256": self.previous_verification_sha256,
"expected_source_capture_result_sha256": self.expected_source_capture_result_sha256,
"expected_source_capture_execution_digest": self.expected_source_capture_execution_digest,
"expected_job_id": self.expected_job_id,
"expected_execution_digest": self.expected_execution_digest,
"required_capability": self.required_capability,
"adapter": self.adapter,
"authorization_id": self.authorization_id,
"idempotency_key": self.idempotency_key,
"reason": self.reason,
}
class CanonicalBridgeInitialExecutionResolver:
"""Resolve one agent-runtime envelope from the canonical governed Bridge."""
def __init__(self, base_url: str, control_token: str) -> None:
self.base_url = base_url.rstrip("/")
self.control_token = control_token
def __call__(
self,
task_id: str,
expected_job_id: str,
required_capability: str,
adapter: str,
runtime_input: Mapping[str, Any],
) -> dict[str, Any]:
body = {
"task_id": task_id,
"job_id": expected_job_id,
"required_capabilities": [required_capability],
"execution": {
"action": "agent_runtime",
"adapter": adapter,
"capability_scope": [required_capability],
"runtime_input": dict(runtime_input),
},
}
request = urllib.request.Request(
self.base_url + "/v2/execution-envelope",
method="POST",
data=_canonical(body),
headers={
"Authorization": "Bearer " + self.control_token,
"Content-Type": "application/json",
"Accept": "application/json",
},
)
try:
with urllib.request.urlopen(request, timeout=15) as response:
raw, status = response.read(), response.status
except urllib.error.HTTPError as exc:
raw, status = exc.read(), exc.code
try:
value = json.loads(raw.decode("utf-8"))
except (UnicodeDecodeError, json.JSONDecodeError) as exc:
raise InitialExecutionProjectionError(
"CANONICAL_EXECUTION_RESPONSE_INVALID", 502
) from exc
if not isinstance(value, Mapping):
raise InitialExecutionProjectionError(
"CANONICAL_EXECUTION_RESPONSE_INVALID", 502
)
if status != 200:
raise InitialExecutionProjectionError(
str(value.get("error") or "CANONICAL_EXECUTION_RESOLUTION_FAILED"),
502 if status >= 500 else 409,
)
return dict(value)
class InitialExecutionProjectionStore:
"""Apply the exact initial projection through one durable CAS transaction."""
allows_supersession_child = False
def __init__(
self,
db_path: Path,
resolver: Callable[
[str, str, str, str, Mapping[str, Any]], Mapping[str, Any]
],
) -> None:
self.db_path = Path(db_path)
self.resolver = resolver
def _connect(self) -> sqlite3.Connection:
connection = sqlite3.connect(self.db_path, timeout=30.0)
connection.row_factory = sqlite3.Row
connection.execute("PRAGMA foreign_keys=ON")
connection.execute("PRAGMA busy_timeout=30000")
return connection
def _validate_projection_entrypoint(
self, connection: sqlite3.Connection, task_id: str
) -> None:
"""Fence formal lineage children from the legacy projection entrypoint.
A supersession child carries additional append-only lineage evidence that
must be committed with its initial projection. The legacy endpoint has
no such contract, so it must not be able to project one accidentally.
"""
tables = {
str(row[0])
for row in connection.execute(
"SELECT name FROM sqlite_master WHERE type='table'"
)
}
if "task_lineage_supersessions" not in tables:
return
lineage = connection.execute(
"SELECT 1 FROM task_lineage_supersessions WHERE child_task_id=?",
(task_id,),
).fetchone()
if lineage is not None and not self.allows_supersession_child:
raise InitialExecutionProjectionError(
"SUPERSESSION_INITIAL_PROJECTION_ENDPOINT_REQUIRED", 409
)
@staticmethod
def _columns(connection: sqlite3.Connection, table: str) -> dict[str, sqlite3.Row]:
return {
str(row["name"]): row
for row in connection.execute(f'PRAGMA table_info("{table}")')
}
@staticmethod
def _json_value(raw: object, code: str) -> Any:
if isinstance(raw, (Mapping, list)):
return dict(raw) if isinstance(raw, Mapping) else list(raw)
if not isinstance(raw, str):
raise InitialExecutionProjectionError(code, 409)
try:
return json.loads(raw)
except json.JSONDecodeError as exc:
raise InitialExecutionProjectionError(code, 409) from exc
@staticmethod
def _event_table(
connection: sqlite3.Connection,
) -> tuple[str, dict[str, sqlite3.Row]]:
tables = {
row["name"]
for row in connection.execute(
"SELECT name FROM sqlite_master WHERE type='table'"
)
}
for name in ("task_events", "events"):
if name in tables:
columns = InitialExecutionProjectionStore._columns(connection, name)
if "task_id" in columns and "event_type" in columns:
return name, columns
raise InitialExecutionProjectionError("TASK_EVENT_TABLE_UNSUPPORTED", 503)
@classmethod
def _initial_event_chain(
cls, connection: sqlite3.Connection, task_id: str
) -> None:
table, columns = cls._event_table(connection)
ordering = "event_id" if "event_id" in columns else "rowid"
events = [
str(row[0])
for row in connection.execute(
f'SELECT event_type FROM "{table}" WHERE task_id=? ORDER BY {ordering}',
(task_id,),
)
]
if events != ["TASK_CREATED"]:
raise InitialExecutionProjectionError(
"TASK_INITIAL_EVENT_CHAIN_REQUIRED", 409
)
@classmethod
def _insert_event(
cls,
connection: sqlite3.Connection,
task_id: str,
payload: Mapping[str, Any],
) -> None:
table, columns = cls._event_table(connection)
values: dict[str, Any] = {
"task_id": task_id,
"event_type": "TASK_INITIAL_EXECUTION_PROJECTION_AUTHORIZED",
}
payload_text = json.dumps(payload, sort_keys=True, separators=(",", ":"))
if "payload_json" in columns:
values["payload_json"] = payload_text
elif "payload" in columns:
values["payload"] = payload_text
else:
raise InitialExecutionProjectionError("TASK_EVENT_PAYLOAD_UNSUPPORTED", 503)
if "created_at" in columns:
values["created_at"] = _now()
if "agent_id" in columns:
values["agent_id"] = "owner-control"
if "actor_id" in columns:
values["actor_id"] = "owner-control"
names = list(values)
connection.execute(
f'INSERT INTO "{table}" ({",".join(chr(34)+name+chr(34) for name in names)}) '
f'VALUES ({",".join("?" for _ in names)})',
tuple(values[name] for name in names),
)
@staticmethod
def _ensure_receipt_table(connection: sqlite3.Connection) -> None:
connection.execute(
"""
CREATE TABLE IF NOT EXISTS task_initial_execution_projections (
task_id TEXT NOT NULL,
idempotency_key TEXT NOT NULL,
request_sha256 TEXT NOT NULL,
authorization_id TEXT NOT NULL,
expected_job_id TEXT NOT NULL,
execution_digest TEXT NOT NULL,
required_capability TEXT NOT NULL,
adapter TEXT NOT NULL,
expected_revision INTEGER NOT NULL,
applied_revision INTEGER NOT NULL,
created_at TEXT NOT NULL,
PRIMARY KEY(task_id,idempotency_key)
)
"""
)
@staticmethod
def _ensure_source_capture_recovery_table(
connection: sqlite3.Connection,
) -> None:
connection.execute(
"""
CREATE TABLE IF NOT EXISTS task_source_capture_projection_recoveries (
task_id TEXT NOT NULL,
idempotency_key TEXT NOT NULL,
request_sha256 TEXT NOT NULL,
authorization_id TEXT NOT NULL,
expected_job_id TEXT NOT NULL,
source_capture_result_sha256 TEXT NOT NULL,
source_capture_execution_digest TEXT NOT NULL,
execution_digest TEXT NOT NULL,
required_capability TEXT NOT NULL,
adapter TEXT NOT NULL,
expected_revision INTEGER NOT NULL,
applied_revision INTEGER NOT NULL,
attempt INTEGER NOT NULL,
created_at TEXT NOT NULL,
PRIMARY KEY(task_id,idempotency_key)
)
"""
)
@classmethod
def _source_capture_event_chain(
cls, connection: sqlite3.Connection, task_id: str
) -> None:
table, columns = cls._event_table(connection)
ordering = "event_id" if "event_id" in columns else "rowid"
rows = connection.execute(
f'SELECT event_type, payload_json FROM "{table}" '
f'WHERE task_id=? ORDER BY {ordering}',
(task_id,),
).fetchall()
events = [str(row[0]) for row in rows]
if (
len(events) < 5
or events[0] != "TASK_CREATED"
or events.count("TASK_CLAIMED") != 1
or events.count("RESULT_SUBMITTED") != 1
or events.count("TASK_VERIFIED") != 1
or events[-1] != "TASK_VERIFIED"
):
raise InitialExecutionProjectionError(
"SOURCE_CAPTURE_RECOVERY_EVENT_CHAIN_INVALID", 409
)
claim = events.index("TASK_CLAIMED")
result = events.index("RESULT_SUBMITTED")
verified = events.index("TASK_VERIFIED")
heartbeat_positions = [
index for index, event in enumerate(events) if event == "TASK_HEARTBEAT"
]
if (
not heartbeat_positions
or not all(claim < index < result for index in heartbeat_positions)
or not claim < result < verified
or any(
event not in {
"TASK_CREATED",
"TASK_CLAIMED",
"TASK_HEARTBEAT",
"RESULT_SUBMITTED",
"TASK_VERIFIED",
}
for event in events
)
):
raise InitialExecutionProjectionError(
"SOURCE_CAPTURE_RECOVERY_EVENT_CHAIN_INVALID", 409
)
try:
verification_event = json.loads(rows[-1][1])
except (TypeError, json.JSONDecodeError) as exc:
raise InitialExecutionProjectionError(
"SOURCE_CAPTURE_RECOVERY_VERIFICATION_EVENT_INVALID", 409
) from exc
if (
not isinstance(verification_event, Mapping)
or verification_event.get("decision") != "NEEDS_REWORK"
or verification_event.get("next_state") != "QUEUED"
):
raise InitialExecutionProjectionError(
"SOURCE_CAPTURE_RECOVERY_VERIFICATION_EVENT_INVALID", 409
)
def _load_source_capture_recovery(
self,
connection: sqlite3.Connection,
task_id: str,
request: SourceCaptureProjectionRecoveryRequest,
) -> tuple[sqlite3.Row, dict[str, Any], dict[str, Any]]:
columns = self._columns(connection, "tasks")
required = {
"task_id", "goal", "instructions", "success_criteria_json",
"constraints_json", "required_capabilities_json", "metadata_json",
"status", "attempt", "revision", "claimed_by", "lease_token_hash",
"lease_expires_at", "result_json", "verification_json",
}
if not required.issubset(columns):
raise InitialExecutionProjectionError(
"TASK_SCHEMA_SOURCE_CAPTURE_RECOVERY_UNSUPPORTED", 503
)
task = connection.execute(
"SELECT * FROM tasks WHERE task_id=?", (task_id,)
).fetchone()
if task is None:
raise InitialExecutionProjectionError("TASK_NOT_FOUND", 404)
self._validate_projection_entrypoint(connection, task_id)
if (
str(task["status"]) != request.expected_status
or int(task["revision"]) != request.expected_revision
or int(task["attempt"]) != request.expected_attempt
):
raise InitialExecutionProjectionError(
"SOURCE_CAPTURE_PROJECTION_RECOVERY_CAS_MISMATCH", 409
)
if task["claimed_by"] not in (None, ""):
raise InitialExecutionProjectionError("TASK_ALREADY_CLAIMED", 409)
if task["lease_token_hash"] not in (None, "") or task["lease_expires_at"] not in (None, ""):
raise InitialExecutionProjectionError("ACTIVE_LEASE_DENY", 409)
metadata = self._json_value(task["metadata_json"], "TASK_METADATA_INVALID")
capabilities = self._json_value(
task["required_capabilities_json"], "TASK_CAPABILITIES_INVALID"
)
result = self._json_value(
task["result_json"], "SOURCE_CAPTURE_RESULT_INVALID"
)
verification = self._json_value(
task["verification_json"], "SOURCE_CAPTURE_VERIFICATION_INVALID"
)
if (
not isinstance(metadata, Mapping)
or not isinstance(capabilities, list)
or not isinstance(result, Mapping)
or not isinstance(verification, Mapping)
):
raise InitialExecutionProjectionError(
"SOURCE_CAPTURE_RECOVERY_STATE_INVALID", 409
)
metadata = dict(metadata)
result = dict(result)
verification = dict(verification)
if "execution" in metadata or "execution_projection" in metadata:
raise InitialExecutionProjectionError("TASK_EXECUTION_ALREADY_PROJECTED", 409)
if capabilities:
raise InitialExecutionProjectionError(
"TASK_INITIAL_CAPABILITIES_MUST_BE_EMPTY", 409
)
if _sha(metadata) != request.expected_metadata_sha256:
raise InitialExecutionProjectionError("TASK_METADATA_DRIFT", 409)
if _sha(capabilities) != request.expected_required_capabilities_sha256:
raise InitialExecutionProjectionError("TASK_CAPABILITIES_DRIFT", 409)
if _sha(result) != request.expected_source_capture_result_sha256:
raise InitialExecutionProjectionError("SOURCE_CAPTURE_RESULT_DRIFT", 409)
if _sha(verification) != request.previous_verification_sha256:
raise InitialExecutionProjectionError("SOURCE_CAPTURE_VERIFICATION_DRIFT", 409)
if verification.get("decision") != "NEEDS_REWORK":
raise InitialExecutionProjectionError(
"SOURCE_CAPTURE_NEEDS_REWORK_VERIFICATION_REQUIRED", 409
)
expected_result = {
"task_id": task_id,
"job_id": request.expected_job_id,
"status": "SUCCEEDED",
"classification": "NEEDS_REWORK_SOURCE_CAPTURE",
"execution_mode": "source_capture",
"execution_digest": request.expected_source_capture_execution_digest,
"changed_files": [],
"writer_lease": "NONE",
"verification_state": "NEEDS_REWORK",
"direct_main_write": False,
"production_write": False,
"force_push": False,
"protected_ref_bypass": False,
"secret_material_exposed": False,
}
if any(result.get(name) != expected for name, expected in expected_result.items()):
raise InitialExecutionProjectionError(
"SOURCE_CAPTURE_RESULT_CONTRACT_INVALID", 409
)
self._source_capture_event_chain(connection, task_id)
return task, metadata, result
def _load_and_validate(
self,
connection: sqlite3.Connection,
task_id: str,
request: InitialExecutionProjectionRequest,
) -> tuple[sqlite3.Row, dict[str, sqlite3.Row], dict[str, Any], list[str]]:
columns = self._columns(connection, "tasks")
required = {
"task_id", "goal", "instructions", "success_criteria_json",
"constraints_json", "required_capabilities_json", "metadata_json",
"status", "attempt", "revision", "claimed_by", "lease_token_hash",
"lease_expires_at", "result_json", "verification_json",
}
if not required.issubset(columns):
raise InitialExecutionProjectionError(
"TASK_SCHEMA_INITIAL_EXECUTION_PROJECTION_UNSUPPORTED", 503
)
task = connection.execute(
"SELECT * FROM tasks WHERE task_id=?", (task_id,)
).fetchone()
if task is None:
raise InitialExecutionProjectionError("TASK_NOT_FOUND", 404)
if (
str(task["status"]) != request.expected_status
or int(task["revision"]) != request.expected_revision
or int(task["attempt"]) != request.expected_attempt
):
raise InitialExecutionProjectionError(
"INITIAL_EXECUTION_PROJECTION_CAS_MISMATCH", 409
)
if task["claimed_by"] not in (None, ""):
raise InitialExecutionProjectionError("TASK_ALREADY_CLAIMED", 409)
if task["lease_token_hash"] not in (None, "") or task["lease_expires_at"] not in (None, ""):
raise InitialExecutionProjectionError("ACTIVE_LEASE_DENY", 409)
if task["result_json"] not in (None, "") or task["verification_json"] not in (None, ""):
raise InitialExecutionProjectionError("TASK_LIFECYCLE_NOT_INITIAL", 409)
metadata = self._json_value(task["metadata_json"], "TASK_METADATA_INVALID")
capabilities = self._json_value(
task["required_capabilities_json"], "TASK_CAPABILITIES_INVALID"
)
if not isinstance(metadata, Mapping) or not isinstance(capabilities, list):
raise InitialExecutionProjectionError("TASK_INITIAL_STATE_INVALID", 409)
metadata = dict(metadata)
if "execution" in metadata or "execution_projection" in metadata:
raise InitialExecutionProjectionError("TASK_EXECUTION_ALREADY_PROJECTED", 409)
if capabilities:
raise InitialExecutionProjectionError(
"TASK_INITIAL_CAPABILITIES_MUST_BE_EMPTY", 409
)
if _sha(metadata) != request.expected_metadata_sha256:
raise InitialExecutionProjectionError("TASK_METADATA_DRIFT", 409)
if _sha(capabilities) != request.expected_required_capabilities_sha256:
raise InitialExecutionProjectionError("TASK_CAPABILITIES_DRIFT", 409)
self._initial_event_chain(connection, task_id)
return task, columns, metadata, capabilities
@staticmethod
def _runtime_input(task: sqlite3.Row) -> dict[str, Any]:
try:
criteria = json.loads(task["success_criteria_json"])
constraints = json.loads(task["constraints_json"])
except (TypeError, json.JSONDecodeError) as exc:
raise InitialExecutionProjectionError("TASK_RUNTIME_INPUT_INVALID", 409) from exc
if not isinstance(criteria, list) or not isinstance(constraints, Mapping):
raise InitialExecutionProjectionError("TASK_RUNTIME_INPUT_INVALID", 409)
return {
"goal": str(task["goal"]),
"instructions": str(task["instructions"]),
"success_criteria": criteria,
"constraints": dict(constraints),
"scope": {"scope_type": "legacy", "tenant_id": None, "project_id": None},
"trace_id": str(task["task_id"]),
}
def _projection_event_extension(
self,
connection: sqlite3.Connection,
task_id: str,
request: InitialExecutionProjectionRequest,
execution: Mapping[str, Any],
applied_revision: int,
) -> Mapping[str, Any]:
"""Return server-derived fields for a specialized projection event."""
return {}
def _insert_projection_extension(
self,
connection: sqlite3.Connection,
task_id: str,
request: InitialExecutionProjectionRequest,
execution: Mapping[str, Any],
event_payload: Mapping[str, Any],
applied_revision: int,
) -> None:
"""Persist specialized evidence in the caller's projection transaction."""
return None
def project(
self,
task_id: str,
request: InitialExecutionProjectionRequest,
) -> dict[str, Any]:
task_id = _require_string(task_id, "TASK_ID_INVALID", TASK_RE)
if request.authorization_id != _required_authorization_id():
raise InitialExecutionProjectionError("AUTHORIZATION_ID_MISMATCH", 403)
request_sha = _sha(request.public())
with self._connect() as connection:
self._validate_projection_entrypoint(connection, task_id)
self._ensure_receipt_table(connection)
replay = connection.execute(
"SELECT * FROM task_initial_execution_projections "
"WHERE task_id=? AND idempotency_key=?",
(task_id, request.idempotency_key),
).fetchone()
if replay is not None:
if replay["request_sha256"] != request_sha:
raise InitialExecutionProjectionError("IDEMPOTENCY_CONFLICT", 409)
connection.commit()
return {
"task_id": task_id,
"status": "QUEUED",
"attempt": 0,
"revision": int(replay["applied_revision"]),
"job_id": replay["expected_job_id"],
"execution_digest": replay["execution_digest"],
"required_capability": replay["required_capability"],
"adapter": replay["adapter"],
"authorization_id": replay["authorization_id"],
"idempotent": True,
}
with self._connect() as connection:
task, _, _, _ = self._load_and_validate(connection, task_id, request)
runtime_input = self._runtime_input(task)
resolved = dict(
self.resolver(
task_id,
request.expected_job_id,
request.required_capability,
request.adapter,
runtime_input,
)
)
binding = GovernedExecutionBinding.from_mapping(resolved)
if binding.task_id != task_id or binding.job_id != request.expected_job_id:
raise InitialExecutionProjectionError("GOVERNED_BINDING_CONFLICT", 409)
execution = validate_execution_envelope(resolved, binding=binding)
if (
execution.get("action") != "agent_runtime"
or execution.get("adapter") != request.adapter
or execution.get("capability_scope") != [request.required_capability]
or execution.get("change_set") != []
or execution.get("verification") != []
or execution.get("governance", {}).get("writer_lease") is not False
):
raise InitialExecutionProjectionError("AGENT_RUNTIME_ENVELOPE_INVALID", 409)
if execution["execution_digest"] != request.expected_execution_digest:
raise InitialExecutionProjectionError("EXECUTION_DIGEST_DRIFT", 409)
with self._connect() as connection:
connection.execute("BEGIN IMMEDIATE")
self._ensure_receipt_table(connection)
replay = connection.execute(
"SELECT * FROM task_initial_execution_projections "
"WHERE task_id=? AND idempotency_key=?",
(task_id, request.idempotency_key),
).fetchone()
if replay is not None:
if replay["request_sha256"] != request_sha:
raise InitialExecutionProjectionError("IDEMPOTENCY_CONFLICT", 409)
connection.commit()
return {
"task_id": task_id,
"status": "QUEUED",
"attempt": 0,
"revision": int(replay["applied_revision"]),
"job_id": replay["expected_job_id"],
"execution_digest": replay["execution_digest"],
"required_capability": replay["required_capability"],
"adapter": replay["adapter"],
"authorization_id": replay["authorization_id"],
"idempotent": True,
}
task, _, metadata, _ = self._load_and_validate(connection, task_id, request)
new_metadata = dict(metadata)
new_metadata["execution"] = execution
new_metadata["execution_projection"] = {
"schema": "aios.online-agent.task-projection.v1",
"task_id": task_id,
"job_id": request.expected_job_id,
"execution_digest": execution["execution_digest"],
}
applied_revision = request.expected_revision + 1
cursor = connection.execute(
"""
UPDATE tasks
SET metadata_json=?, required_capabilities_json=?,
revision=?, updated_at=?
WHERE task_id=? AND status=? AND revision=? AND attempt=?
AND claimed_by IS NULL AND lease_token_hash IS NULL
AND lease_expires_at IS NULL AND result_json IS NULL
AND verification_json IS NULL
AND metadata_json=? AND required_capabilities_json=?
""",
(
json.dumps(new_metadata, sort_keys=True, separators=(",", ":")),
json.dumps([request.required_capability], separators=(",", ":")),
applied_revision,
_now(),
task_id,
request.expected_status,
request.expected_revision,
request.expected_attempt,
task["metadata_json"],
task["required_capabilities_json"],
),
)
if cursor.rowcount != 1:
raise InitialExecutionProjectionError(
"INITIAL_EXECUTION_PROJECTION_CAS_MISMATCH", 409
)
event_payload = {
"schema": "aios.task-initial-execution-projection.event.v1",
"task_id": task_id,
"job_id": request.expected_job_id,
"authorization_id": request.authorization_id,
"idempotency_key": request.idempotency_key,
"reason": request.reason,
"action": "agent_runtime",
"adapter": request.adapter,
"required_capability": request.required_capability,
"execution_digest": execution["execution_digest"],
"previous_revision": request.expected_revision,
"applied_revision": applied_revision,
"attempt": request.expected_attempt,
"request_sha256": request_sha,
"writer_lease": False,
"main_write": False,
"production_write": False,
}
extension = dict(
self._projection_event_extension(
connection,
task_id,
request,
execution,
applied_revision,
)
)
if set(extension).intersection(event_payload):
raise InitialExecutionProjectionError(
"INITIAL_EXECUTION_PROJECTION_EVENT_EXTENSION_CONFLICT", 500
)
event_payload.update(extension)
self._insert_event(connection, task_id, event_payload)
connection.execute(
"""
INSERT INTO task_initial_execution_projections(
task_id,idempotency_key,request_sha256,authorization_id,
expected_job_id,execution_digest,required_capability,adapter,
expected_revision,applied_revision,created_at
) VALUES (?,?,?,?,?,?,?,?,?,?,?)
""",
(
task_id,
request.idempotency_key,
request_sha,
request.authorization_id,
request.expected_job_id,
execution["execution_digest"],
request.required_capability,
request.adapter,
request.expected_revision,
applied_revision,
_now(),
),
)
self._insert_projection_extension(
connection,
task_id,
request,
execution,
event_payload,
applied_revision,
)
connection.commit()
return {
"task_id": task_id,
"status": "QUEUED",
"attempt": 0,
"revision": applied_revision,
"job_id": request.expected_job_id,
"execution_digest": execution["execution_digest"],
"required_capability": request.required_capability,
"adapter": request.adapter,
"authorization_id": request.authorization_id,
"idempotent": False,
}
def project_from_source_capture(
self,
task_id: str,
request: SourceCaptureProjectionRecoveryRequest,
) -> dict[str, Any]:
task_id = _require_string(task_id, "TASK_ID_INVALID", TASK_RE)
if request.authorization_id != _required_authorization_id():
raise InitialExecutionProjectionError("AUTHORIZATION_ID_MISMATCH", 403)
request_sha = _sha(request.public())
def replay_result(row: sqlite3.Row) -> dict[str, Any]:
return {
"task_id": task_id,
"status": "QUEUED",
"attempt": int(row["attempt"]),
"revision": int(row["applied_revision"]),
"job_id": row["expected_job_id"],
"source_capture_execution_digest": row[
"source_capture_execution_digest"
],
"execution_digest": row["execution_digest"],
"required_capability": row["required_capability"],
"adapter": row["adapter"],
"authorization_id": row["authorization_id"],
"recovery_from_source_capture": True,
"idempotent": True,
}
with self._connect() as connection:
self._ensure_source_capture_recovery_table(connection)
replay = connection.execute(
"SELECT * FROM task_source_capture_projection_recoveries "
"WHERE task_id=? AND idempotency_key=?",
(task_id, request.idempotency_key),
).fetchone()
if replay is not None:
if replay["request_sha256"] != request_sha:
raise InitialExecutionProjectionError("IDEMPOTENCY_CONFLICT", 409)
connection.commit()
return replay_result(replay)
with self._connect() as connection:
task, _, result = self._load_source_capture_recovery(
connection, task_id, request
)
runtime_input = self._runtime_input(task)
resolved = dict(
self.resolver(
task_id,
request.expected_job_id,
request.required_capability,
request.adapter,
runtime_input,
)
)
binding = GovernedExecutionBinding.from_mapping(resolved)
if binding.task_id != task_id or binding.job_id != request.expected_job_id:
raise InitialExecutionProjectionError("GOVERNED_BINDING_CONFLICT", 409)
result_binding = {
"task_id": result.get("task_id"),
"job_id": result.get("job_id"),
"repository": result.get("repository"),
"base_oid": result.get("base_oid"),
"expected_branch_oid": result.get("expected_branch_oid"),
"target_branch": result.get("target_branch"),
"generation": result.get("generation"),
}
expected_binding = {
"task_id": binding.task_id,
"job_id": binding.job_id,
"repository": binding.repository,
"base_oid": binding.base_oid,
"expected_branch_oid": binding.expected_branch_oid,
"target_branch": binding.target_branch,
"generation": binding.generation,
}
if result_binding != expected_binding:
raise InitialExecutionProjectionError(
"SOURCE_CAPTURE_GOVERNED_BINDING_CONFLICT", 409
)
execution = validate_execution_envelope(resolved, binding=binding)
if (
execution.get("action") != "agent_runtime"
or execution.get("adapter") != request.adapter
or execution.get("capability_scope") != [request.required_capability]
or execution.get("change_set") != []
or execution.get("verification") != []
or execution.get("governance", {}).get("writer_lease") is not False
):
raise InitialExecutionProjectionError("AGENT_RUNTIME_ENVELOPE_INVALID", 409)
if execution["execution_digest"] != request.expected_execution_digest:
raise InitialExecutionProjectionError("EXECUTION_DIGEST_DRIFT", 409)
with self._connect() as connection:
connection.execute("BEGIN IMMEDIATE")
self._ensure_source_capture_recovery_table(connection)
replay = connection.execute(
"SELECT * FROM task_source_capture_projection_recoveries "
"WHERE task_id=? AND idempotency_key=?",
(task_id, request.idempotency_key),
).fetchone()
if replay is not None:
if replay["request_sha256"] != request_sha:
raise InitialExecutionProjectionError("IDEMPOTENCY_CONFLICT", 409)
connection.commit()
return replay_result(replay)
task, metadata, _ = self._load_source_capture_recovery(
connection, task_id, request
)
new_metadata = dict(metadata)
new_metadata["execution"] = execution
new_metadata["execution_projection"] = {
"schema": "aios.online-agent.task-projection.v1",
"task_id": task_id,
"job_id": request.expected_job_id,
"execution_digest": execution["execution_digest"],
}
applied_revision = request.expected_revision + 1
cursor = connection.execute(
"""
UPDATE tasks
SET metadata_json=?, required_capabilities_json=?,
revision=?, updated_at=?
WHERE task_id=? AND status=? AND revision=? AND attempt=?
AND claimed_by IS NULL AND lease_token_hash IS NULL
AND lease_expires_at IS NULL
AND metadata_json=? AND required_capabilities_json=?
AND result_json=? AND verification_json=?
""",
(
json.dumps(new_metadata, sort_keys=True, separators=(",", ":")),
json.dumps([request.required_capability], separators=(",", ":")),
applied_revision,
_now(),
task_id,
request.expected_status,
request.expected_revision,
request.expected_attempt,
task["metadata_json"],
task["required_capabilities_json"],
task["result_json"],
task["verification_json"],
),
)
if cursor.rowcount != 1:
raise InitialExecutionProjectionError(
"SOURCE_CAPTURE_PROJECTION_RECOVERY_CAS_MISMATCH", 409
)
event_payload = {
"schema": "aios.task-initial-execution-projection.event.v1",
"task_id": task_id,
"job_id": request.expected_job_id,
"authorization_id": request.authorization_id,
"idempotency_key": request.idempotency_key,
"reason": request.reason,
"action": "agent_runtime",
"adapter": request.adapter,
"required_capability": request.required_capability,
"source_capture_execution_digest": request.expected_source_capture_execution_digest,
"source_capture_result_sha256": request.expected_source_capture_result_sha256,
"previous_verification_sha256": request.previous_verification_sha256,
"execution_digest": execution["execution_digest"],
"previous_revision": request.expected_revision,
"applied_revision": applied_revision,
"attempt": request.expected_attempt,
"request_sha256": request_sha,
"recovery_from_source_capture": True,
"writer_lease": False,
"main_write": False,
"production_write": False,
}
self._insert_event(connection, task_id, event_payload)
connection.execute(
"""
INSERT INTO task_source_capture_projection_recoveries(
task_id,idempotency_key,request_sha256,authorization_id,
expected_job_id,source_capture_result_sha256,
source_capture_execution_digest,execution_digest,
required_capability,adapter,expected_revision,applied_revision,
attempt,created_at
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)
""",
(
task_id,
request.idempotency_key,
request_sha,
request.authorization_id,
request.expected_job_id,
request.expected_source_capture_result_sha256,
request.expected_source_capture_execution_digest,
execution["execution_digest"],
request.required_capability,
request.adapter,
request.expected_revision,
applied_revision,
request.expected_attempt,
_now(),
),
)
connection.commit()
return {
"task_id": task_id,
"status": "QUEUED",
"attempt": request.expected_attempt,
"revision": applied_revision,
"job_id": request.expected_job_id,
"source_capture_execution_digest": request.expected_source_capture_execution_digest,
"execution_digest": execution["execution_digest"],
"required_capability": request.required_capability,
"adapter": request.adapter,
"authorization_id": request.authorization_id,
"recovery_from_source_capture": True,
"idempotent": False,
}
class InitialExecutionProjectionHandler(BaseHTTPRequestHandler):
store: InitialExecutionProjectionStore | None = None
control_token: str = ""
def log_message(self, *_args: Any) -> None:
return
def _json(self, value: Mapping[str, Any], status: int) -> None:
data = json.dumps(dict(value), sort_keys=True, separators=(",", ":")).encode()
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
def _authorized(self) -> bool:
header = self.headers.get("Authorization", "")
return (
header.startswith("Bearer ")
and bool(self.control_token)
and hmac.compare_digest(header[7:], self.control_token)
)
def do_GET(self) -> None:
if self.path == "/health":
self._json(
{"status": "ok", "service": "aios-agent-task-initial-execution-projection"},
200,
)
else:
canonical_match = re.fullmatch(
r"/v1/tasks/([^/]+)/canonical-projection", self.path
)
if canonical_match is None:
self._json({"error": "NOT_FOUND"}, 404)
return
if not self._authorized():
self._json({"error": "UNAUTHORIZED"}, 401)
return
if self.store is None:
self._json({"error": "RUNTIME_UNAVAILABLE"}, 503)
return
status, result = get_canonical_projection(
self.store.db_path, canonical_match.group(1)
)
self._json(result, status)
def do_POST(self) -> None:
initial_match = re.fullmatch(
r"/v1/tasks/([^/]+)/initial-execution-projection", self.path
)
canonical_match = re.fullmatch(
r"/v1/tasks/([^/]+)/canonical-projection-recovery", self.path
)
recovery_match = re.fullmatch(
r"/v1/tasks/([^/]+)/source-capture-projection-recovery", self.path
)
if (
initial_match is None
and recovery_match is None
and canonical_match is None
):
self._json({"error": "NOT_FOUND"}, 404)
return
if not self._authorized():
self._json({"error": "UNAUTHORIZED"}, 401)
return
try:
length = int(self.headers.get("Content-Length", "0"))
except ValueError:
self._json({"error": "CONTENT_LENGTH_INVALID"}, 400)
return
if length < 1 or length > MAX_BODY:
self._json({"error": "REQUEST_SIZE_INVALID"}, 413)
return
try:
value = json.loads(self.rfile.read(length).decode("utf-8"))
if not isinstance(value, Mapping):
raise ValueError
if self.store is None:
raise InitialExecutionProjectionError("RUNTIME_UNAVAILABLE", 503)
if canonical_match is not None:
status, result = recover_canonical_projection(
self.store.db_path, canonical_match.group(1), value
)
self._json(result, status)
return
if initial_match is not None:
request = InitialExecutionProjectionRequest.from_mapping(value)
result = self.store.project(initial_match.group(1), request)
else:
recovery_request = SourceCaptureProjectionRecoveryRequest.from_mapping(
value
)
result = self.store.project_from_source_capture(
recovery_match.group(1), recovery_request
)
self._json(result, 200 if result["idempotent"] else 201)
except InitialExecutionProjectionError as exc:
self._json({"error": exc.code}, exc.status)
except (UnicodeDecodeError, json.JSONDecodeError, ValueError):
self._json({"error": "REQUEST_INVALID"}, 400)
def load_control_token(path: Path) -> str:
if path.is_symlink() or not path.is_file():
raise RuntimeError("INITIAL_EXECUTION_PROJECTION_CONTROL_CREDENTIAL_UNAVAILABLE")
value = path.read_text(encoding="utf-8").strip()
if len(value) < 32:
raise RuntimeError("INITIAL_EXECUTION_PROJECTION_CONTROL_CREDENTIAL_INVALID")
return value
def serve() -> None:
db = Path(os.environ.get("AIOS_AGENT_TASK_DB", "/var/lib/aios-agent-task/state.sqlite3"))
_required_authorization_id()
token_path = Path(
os.environ.get(
"AIOS_AGENT_TASK_CONTROL_TOKEN_FILE",
str(Path(os.environ.get("CREDENTIALS_DIRECTORY", "/run/credentials")) / "agent_task_control_token"),
)
)
token = load_control_token(token_path)
bridge = os.environ.get("AIOS_GOVERNED_WRITE_API_URL", "http://127.0.0.1:18892")
host = os.environ.get("AIOS_TASK_INITIAL_EXECUTION_PROJECTION_HOST", "127.0.0.1")
port = int(os.environ.get("AIOS_TASK_INITIAL_EXECUTION_PROJECTION_PORT", "18943"))
InitialExecutionProjectionHandler.store = InitialExecutionProjectionStore(
db, CanonicalBridgeInitialExecutionResolver(bridge, token)
)
InitialExecutionProjectionHandler.control_token = token
ThreadingHTTPServer((host, port), InitialExecutionProjectionHandler).serve_forever()
if __name__ == "__main__":
serve()