# Datalog accounting policies

Accounting policies answer *how should this event be accounted for?* They are
Datalog-backed rules in `Logistiki.Knowledge.Program`.

## Policy selection

The `policy/2` relation is derived from the event's facts:

```elixir
rule policy(E, :cash_deposit) do
  event_type(E, :deposit_received)
end

rule policy(E, :corporate_wire_fee) do
  event_type(E, :fee_assessed)
  event_fee_type(E, :wire_fee)
  event_entity_type(E, :corporate)
end

rule policy(E, :retail_wire_fee) do
  event_type(E, :fee_assessed)
  event_fee_type(E, :wire_fee)
  event_entity_type(E, :individual)
end

rule policy(E, :internal_transfer) do
  event_type(E, :transfer_settled)
end

rule policy(E, :interest_accrual) do
  event_type(E, :interest_accrued)
end

rule policy(E, :refund_paid) do
  event_type(E, :refund_issued)
end
```

Because policies are derived from multiple facts, the knowledge layer genuinely
*selects* a policy based on the event's properties (event type, fee type, entity
type, product, jurisdiction, ...) rather than hard-coding a mapping.

## Posting templates

Templates answer *which postings should be generated by this policy?* They are
static facts:

```elixir
fact template(:cash_deposit)

facts :template_posting do
  row(:cash_deposit, 1, :debit,  :cash_account,             :event_amount, :event_currency)
  row(:cash_deposit, 2, :credit, :client_liability_account, :event_amount, :event_currency)
end
```

Each template posting spec has a `sequence`, a `direction` (`:debit`/`:credit`),
a symbolic `role`, and the amount/currency variables (`:event_amount` /
`:event_currency` in v0.1.0).

## Account mappings

Account mappings answer *which concrete account code should a symbolic role
resolve to?* They are derived by `account_role/3` rules:

```elixir
rule account_role(E, :client_liability_account, C) do
  event_account(E, C)
end

rule account_role(E, :cash_account, C) do
  event_cash_account(E, C)
end

# Static fallback for roles not carried by the event:
rule account_role(E, R, C) do
  account_role_static(R, C)
  event_type(E, _)
end
```

A static fallback is provided for roles an event does not carry directly (e.g.
`account_role_static(:interest_expense_account, "EXPENSES:INTEREST")`).

## Constraints

`requires_dimension/2` facts declare which dimensions a policy requires (e.g.
`requires_dimension(:cash_deposit, :entity_id)`). The runtime records these for
audit; hard invariants are enforced in Elixir.

## Business rules vs. accounting policies vs. ledger invariants

Three distinct rule categories (see `Logistiki.Knowledge.Rules`):

- **Business rules** (Datalog): should the event be processed / blocked /
  approved?
- **Accounting policies** (Datalog): which policy, template, roles, dimensions?
- **Ledger invariants** (pure Elixir): debits equal credits, postings positive,
  posted journals immutable, etc. — **never** Datalog.

Datalog may say what should happen. Elixir enforces what must always be true.
