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

90 lines
2.8 KiB
Python

"""Owner approval gate for architecture changes.
Architecture changes may be proposed, reviewed and optimized by agents, but they
must not be implemented until owner approval is recorded. This gate sits before
implementation and before promotion.
"""
from __future__ import annotations
from dataclasses import asdict, dataclass, field
from datetime import datetime, timezone
from typing import Any
def utc_now() -> str:
return datetime.now(timezone.utc).isoformat()
@dataclass(frozen=True)
class ArchitectureOwnerApprovalRequest:
request_id: str
change_id: str
title: str
reason: str
risk: str
architect_decision: str
status: str = "pending_owner_approval"
created_at: str = field(default_factory=utc_now)
def to_dict(self) -> dict[str, Any]:
return asdict(self)
@dataclass(frozen=True)
class ArchitectureOwnerDecision:
request_id: str
change_id: str
decision: str
decided_by: str
reason: str = ""
decided_at: str = field(default_factory=utc_now)
def to_dict(self) -> dict[str, Any]:
return asdict(self)
class ArchitectureOwnerGate:
"""Blocks architecture implementation until owner explicitly approves."""
def create_request(self, change: dict[str, Any], architect_decision: dict[str, Any]) -> ArchitectureOwnerApprovalRequest:
return ArchitectureOwnerApprovalRequest(
request_id=f"ARCH-OWNER-{change.get('change_id', change.get('id', 'unknown'))}",
change_id=change.get("change_id", change.get("id", "unknown")),
title=change.get("title", "architecture change"),
reason=change.get("reason", "architecture impact requires owner approval"),
risk=change.get("risk", "medium"),
architect_decision=architect_decision.get("status", "reviewed"),
)
def can_implement(self, request: dict[str, Any], decision: dict[str, Any] | None = None) -> dict[str, Any]:
if not decision:
return {
"allowed": False,
"status": "waiting_owner_approval",
"reason": "architecture change requires owner approval before implementation",
"request": request,
}
if decision.get("decision") == "approved":
return {
"allowed": True,
"status": "owner_approved",
"reason": decision.get("reason", "approved by owner"),
"request": request,
"decision": decision,
}
return {
"allowed": False,
"status": "owner_rejected",
"reason": decision.get("reason", "rejected by owner"),
"request": request,
"decision": decision,
}
__all__ = [
"ArchitectureOwnerApprovalRequest",
"ArchitectureOwnerDecision",
"ArchitectureOwnerGate",
]