# Consistency Validation

EntryTarget provides multiple ways to verify the consistency and integrity of your financial data.

## Automated Validation

### Integrity Endpoint

Use `GET /integrity` for comprehensive row-level validation. See [Integrity API](/docs/api-reference/integrity.md).

### Real-Time Validation

Every write operation automatically validates the integrity of involved accounts before processing. If any account has been tampered with, the operation is rejected immediately.

## Manual SQL Queries

Run these queries directly on the database (via the read replica) for deeper validation.

### Sum of All Balances Must Be Zero

The fundamental double-entry rule — if this isn't zero, something is wrong:

```sql
SELECT SUM(balance) FROM account;
-- Must return 0
```

### Per-Asset Balance Must Be Zero

Each currency must independently balance to zero:

```sql
SELECT asset, SUM(balance)::bigint AS total
FROM account
GROUP BY asset
ORDER BY asset;
-- Every row must show total = 0
```

### Debits Must Equal Credits

```sql
SELECT
    SUM(amount) FILTER (WHERE operation = 'DEBIT')  AS total_debits,
    SUM(amount) FILTER (WHERE operation = 'CREDIT') AS total_credits,
    SUM(amount) FILTER (WHERE operation = 'DEBIT') -
    SUM(amount) FILTER (WHERE operation = 'CREDIT') AS difference
FROM ledger;
-- difference must be 0
```

### Account Version Must Be Sequential

No gaps allowed in `account_version` — each operation increments by exactly 1:

```sql
SELECT * FROM (
    SELECT account_id, account_version,
           LAG(account_version) OVER (
               PARTITION BY account_id ORDER BY account_version
           ) AS prev
    FROM ledger
) t
WHERE prev IS NOT NULL AND account_version != prev + 1;
-- Must return zero rows
```

### Post-Balance Must Evolve Correctly

Each ledger line's `account_post_balance` must be mathematically derived from the previous balance:

```sql
SELECT * FROM (
    SELECT operation, amount, account_post_balance,
           LAG(account_post_balance) OVER (
               PARTITION BY account_id ORDER BY account_version
           ) AS prev_balance
    FROM ledger
) t
WHERE prev_balance IS NOT NULL
  AND account_post_balance != CASE
      WHEN operation = 'CREDIT' THEN prev_balance + amount
      WHEN operation = 'DEBIT'  THEN prev_balance - amount
  END;
-- Must return zero rows
```

## Archive Consistency Queries

After archiving ledger data, run these additional validations.

### All Records Must Be Full (Except the Last)

```sql
SELECT la.account_id, la.id, la.line_count, la.version_to
FROM ledger_archive la
WHERE la.line_count < 1000
  AND la.version_to != (
      SELECT MAX(version_to)
      FROM ledger_archive
      WHERE account_id = la.account_id
  );
-- Must return zero rows
```

### Balance Continuity Between Records

```sql
SELECT a.account_id, a.version_to, a.balance_after, b.balance_before
FROM ledger_archive a
JOIN ledger_archive b
  ON a.account_id = b.account_id
  AND b.version_from = a.version_to + 1
WHERE a.balance_after != b.balance_before;
-- Must return zero rows
```

### Archive-to-Live Ledger Continuity

```sql
SELECT la.account_id, la.balance_after, l.account_post_balance, l.operation, l.amount
FROM ledger_archive la
JOIN LATERAL (
    SELECT * FROM ledger
    WHERE account_id = la.account_id
    ORDER BY account_version ASC
    LIMIT 1
) l ON true
WHERE la.version_to = (
    SELECT MAX(version_to) FROM ledger_archive WHERE account_id = la.account_id
);
-- Verify balance_after connects to the first live ledger line
```

## Recommended Schedule

| Validation             | Frequency     | Method           |
| ---------------------- | ------------- | ---------------- |
| Row-level integrity    | Daily         | `GET /integrity` |
| Sum of balances        | Daily         | SQL query        |
| Per-asset balance      | Daily         | SQL query        |
| Version continuity     | Weekly        | SQL query        |
| Post-balance evolution | Weekly        | SQL query        |
| Archive consistency    | After archive | SQL queries      |

{% hint style="info" %}
All manual queries should be run on the **read replica** to avoid impacting write performance.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://entrytarget.gitbook.io/docs/maintenance/consistency-validation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
