Skip to content

ADR-005 — Adapter Interface Method Contracts

Status: Accepted
Date: 2026-05-21

Decision

Three interface contracts with the following method signatures:

CommerceAdapterContract

php
interface CommerceAdapterContract
{
    // Reads — called by agent during reasoning
    public function getOrder(string $id): OrderDTO;
    public function findOrdersByEmail(string $email): Collection;
    public function findOrdersByPhone(string $phone): Collection;
    public function getCustomer(string $id): CustomerDTO;

    // Executes — called ONLY by ExecuteApprovalJob after human approval
    public function executeRefund(string $orderId, float $amount, string $reason): bool;
    public function executeCancelOrder(string $orderId, string $reason): bool;
    public function executeAddNote(string $orderId, string $note): bool;
}

ProductAdapterContract

php
interface ProductAdapterContract
{
    public function searchProducts(string $query): Collection;
    public function getProduct(string $id): ProductDTO;
}

ChannelAdapterContract

php
interface ChannelAdapterContract
{
    // Reads
    public function listOpenConversations(): Collection;
    public function getConversation(string $id): ConversationDTO;
    public function getMessages(string $conversationId): Collection;

    // Execute — requires prior approval
    public function sendReply(string $conversationId, string $body): bool;
    public function resolveConversation(string $conversationId): bool;

    // Execute — no approval needed (internal, reversible)
    public function assignConversation(string $conversationId, int $agentId): bool;
}

Return Types

All adapters return typed readonly DTOs — not Eloquent models, not raw arrays. This ensures the agent layer is completely decoupled from the underlying platform.

php
readonly class OrderDTO {
    public function __construct(
        public string $id,
        public string $reference,
        public string $status,
        public float  $total,
        public string $currency,
        public string $customerEmail,
        public string $customerName,
        public string $customerPhone,
        public array  $lines,        // [{name, qty, unit_price}]
        public string $createdAt,
    ) {}
}

Key Design Principle

Adapters never create approval requests. They only read or execute. The agent/orchestrator layer decides what needs approval; the adapter only acts after approval is granted.

Consequences

  • Swapping LunarPHP for WooCommerce requires zero changes outside the adapter class
  • The agent always receives the same DTO shape regardless of the backend platform
  • execute* methods on CommerceAdapter and sendReply/resolveConversation on ChannelAdapter are only ever called from ExecuteApprovalJob