Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions intelligence/ecdt/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""Enterprise Cognitive Decision Trust (ECDT)."""

from .application_validation import (
ApplicationEvidence,
ApplicationValidation,
ValidationResult,
ValidationStatus,
)
from .application_validation_gate import ApplicationValidationGate

__all__ = [
"ApplicationEvidence",
"ApplicationValidation",
"ApplicationValidationGate",
"ValidationResult",
"ValidationStatus",
]
94 changes: 94 additions & 0 deletions intelligence/ecdt/application_validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"""Deterministic application validation primitives for AEON MATRIX ECDT."""

from __future__ import annotations

from dataclasses import dataclass, field
from enum import Enum
from typing import Mapping


class ValidationStatus(str, Enum):
APPROVED = "APPROVED"
REJECTED = "REJECTED"
INSUFFICIENT_EVIDENCE = "INSUFFICIENT_EVIDENCE"


@dataclass(frozen=True)
class ApplicationEvidence:
application_id: str
source: str
facts: Mapping[str, object] = field(default_factory=dict)
verified: bool = False


@dataclass(frozen=True)
class ValidationResult:
application_id: str
status: ValidationStatus
reasons: tuple[str, ...]
evidence_count: int
verified_evidence_count: int

@property
def approved(self) -> bool:
return self.status is ValidationStatus.APPROVED


class ApplicationValidation:
"""Evaluates evidence without executing operational actions."""

def __init__(self, minimum_verified_evidence: int = 1) -> None:
if minimum_verified_evidence < 1:
raise ValueError("minimum_verified_evidence must be >= 1")

self.minimum_verified_evidence = minimum_verified_evidence

def validate(
self,
application_id: str,
evidence: list[ApplicationEvidence],
) -> ValidationResult:
if not application_id.strip():
raise ValueError("application_id must not be empty")

relevant = tuple(
item for item in evidence
if item.application_id == application_id
)

if not relevant:
return ValidationResult(
application_id=application_id,
status=ValidationStatus.INSUFFICIENT_EVIDENCE,
reasons=("NO_EVIDENCE",),
evidence_count=0,
verified_evidence_count=0,
)

verified = tuple(item for item in relevant if item.verified)

if len(verified) < self.minimum_verified_evidence:
return ValidationResult(
application_id=application_id,
status=ValidationStatus.INSUFFICIENT_EVIDENCE,
reasons=("VERIFIED_EVIDENCE_BELOW_THRESHOLD",),
evidence_count=len(relevant),
verified_evidence_count=len(verified),
)

if any(not item.source.strip() for item in verified):
return ValidationResult(
application_id=application_id,
status=ValidationStatus.REJECTED,
reasons=("INVALID_EVIDENCE_SOURCE",),
evidence_count=len(relevant),
verified_evidence_count=len(verified),
)

return ValidationResult(
application_id=application_id,
status=ValidationStatus.APPROVED,
reasons=("EVIDENCE_THRESHOLD_SATISFIED",),
evidence_count=len(relevant),
verified_evidence_count=len(verified),
)
36 changes: 36 additions & 0 deletions intelligence/ecdt/application_validation_gate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Decision gate for ECDT application validation."""

from __future__ import annotations

from .application_validation import (
ApplicationEvidence,
ApplicationValidation,
ValidationResult,
)


class ApplicationValidationGate:
"""
Fail-closed gate.

The gate validates evidence only. It does not execute the requested
business action and therefore preserves separation between intelligence,
governance, and operational execution.
"""

def __init__(self, validator: ApplicationValidation | None = None) -> None:
self.validator = validator or ApplicationValidation()

def evaluate(
self,
application_id: str,
evidence: list[ApplicationEvidence],
) -> ValidationResult:
return self.validator.validate(application_id, evidence)

def allows(
self,
application_id: str,
evidence: list[ApplicationEvidence],
) -> bool:
return self.evaluate(application_id, evidence).approved
93 changes: 93 additions & 0 deletions services/guardian/execution/authorization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
from uuid import uuid4


@dataclass(frozen=True)
class ExecutionAuthorization:
"""
Guardian-issued execution authority.

The authority is bound to one decision and one action.
V1 provides architectural authority semantics; it is not
a cryptographically signed security token.
"""

authorization_id: str
decision_id: str
action: str
issued_by: str
policy_status: str
approval_status: str
issued_at: datetime
expires_at: datetime


class AuthorizationIssuer:
ISSUER = "GUARDIAN"

def issue(
self,
*,
decision_id,
action,
policy_status,
approval_status,
ttl_seconds=300,
):
if policy_status != "APPROVED":
raise ValueError("POLICY_NOT_APPROVED")

if approval_status != "APPROVED":
raise ValueError("APPROVAL_NOT_APPROVED")

if not decision_id:
raise ValueError("DECISION_ID_REQUIRED")

if not action:
raise ValueError("ACTION_REQUIRED")

issued_at = datetime.now(timezone.utc)

return ExecutionAuthorization(
authorization_id=str(uuid4()),
decision_id=decision_id,
action=action,
issued_by=self.ISSUER,
policy_status=policy_status,
approval_status=approval_status,
issued_at=issued_at,
expires_at=issued_at + timedelta(seconds=ttl_seconds),
)

def verify(
self,
authority,
*,
decision_id,
action,
):
if not isinstance(authority, ExecutionAuthorization):
return False

if authority.issued_by != self.ISSUER:
return False

if authority.policy_status != "APPROVED":
return False

if authority.approval_status != "APPROVED":
return False

if authority.decision_id != decision_id:
return False

if authority.action != action:
return False

now = datetime.now(timezone.utc)

if authority.expires_at <= now:
return False

return True
81 changes: 70 additions & 11 deletions services/guardian/execution/execution_layer.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,94 @@
from services.guardian.execution.action_executor import ActionExecutor
from services.guardian.execution.approval_gate import ApprovalGate
from services.guardian.execution.workflow_engine import WorkflowEngine
from services.guardian.execution.audit_trail import AuditTrail
from services.guardian.execution.authorization import AuthorizationIssuer
from services.guardian.governance.policy_engine import PolicyEngine
from services.guardian.governance.approval_gate import ApprovalGate


class AutonomousExecutionLayer:
"""
Fail-closed execution boundary.

Execution requires all of the following:

1. Guardian policy approval.
2. Guardian approval gate approval.
3. A valid Guardian-issued ExecutionAuthorization.
4. Authority bound to the exact decision and action.

Confidence is evidence, not execution authority.
Boolean authorization flags are not trusted.
"""

def __init__(self):
self.executor = ActionExecutor()
self.policy = PolicyEngine()
self.approval = ApprovalGate()
self.authority = AuthorizationIssuer()
self.workflow = WorkflowEngine()
self.audit = AuditTrail()

def run(self, decision):

approval = self.approval.approve(
decision
)
policy = self.policy.evaluate(decision)
approval = self.approval.request(policy)

if not approval["approved"]:
return {
"status": "WAITING_HUMAN_APPROVAL",
"approval": approval
"status": (
"WAITING_HUMAN_APPROVAL"
if approval["human_required"]
else "BLOCKED"
),
"policy": policy,
"approval": approval,
}

decision_id = decision.get("decision_id")
action = decision.get("action")
execution_authority = decision.get("execution_authority")

if not decision_id:
return {
"status": "BLOCKED",
"reason": "DECISION_ID_REQUIRED",
"policy": policy,
"approval": approval,
}

if not action:
return {
"status": "BLOCKED",
"reason": "ACTION_REQUIRED",
"policy": policy,
"approval": approval,
}

if not self.authority.verify(
execution_authority,
decision_id=decision_id,
action=action,
):
return {
"status": "BLOCKED",
"reason": "EXECUTION_AUTHORIZATION_REQUIRED",
"policy": policy,
"approval": approval,
}

result = self.executor.execute(
decision["action"]
)
result = self.executor.execute(action)

return {
"status": "EXECUTED",
"policy": policy,
"approval": approval,
"authorization": {
"authorization_id": execution_authority.authorization_id,
"issued_by": execution_authority.issued_by,
"decision_id": execution_authority.decision_id,
"action": execution_authority.action,
},
"workflow": self.workflow.build(decision),
"execution": result,
"audit": self.audit.record(result)
"audit": self.audit.record(result),
}
Loading
Loading