# 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.