Appearance
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 andsendReply/resolveConversationon ChannelAdapter are only ever called fromExecuteApprovalJob