> ## Documentation Index
> Fetch the complete documentation index at: https://finance.qwedai.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Design and architecture

> How QWED Finance is built: the guard modules, the engine each one uses, how receipts are made, and the design rules every check follows.

This page describes how QWED Finance is organised inside.

## Where it runs

QWED Finance is a library. It runs inside your process and makes no network calls. Your code calls a guard with the model's output, and decides what to do with the result: act on it, hold it, or send it to a person.

```mermaid theme={null}
flowchart LR
    Model["Language model"] -->|"figure, decision,<br/>message or query"| App["Your application"]
    App -->|"calls a guard"| QWED["QWED Finance<br/>(in your process)"]
    QWED -->|"result and, for some calls,<br/>a receipt"| App
    App -->|"verified"| Act["Your bank, payment<br/>or data systems"]
    App -->|"rejected"| Hold["Hold, retry or<br/>human review"]
```

## Guard architecture

### Component diagram

```mermaid theme={null}
graph TB
    subgraph "qwed_finance/"
        direction TB

        subgraph "Guards"
            CG["compliance_guard.py<br/>AML, KYC, limits, sanctions"]
            CAL["calendar_guard.py<br/>Day-count conventions"]
            DG["derivatives_guard.py<br/>Black-Scholes, margin"]
            MG["message_guard.py<br/>ISO 20022, SWIFT MT"]
            QG["query_guard.py<br/>SQL safety"]
            XG["cross_guard.py<br/>Several guards at once"]
            BG["bond_guard.py<br/>YTM, duration"]
            FXG["fx_guard.py<br/>FX rates"]
            RG["risk_guard.py<br/>VaR, ratios"]
            ISO["guards/iso_guard.py<br/>ISO 20022 JSON"]
            TG["guards/trading_guard.py<br/>Order parameters"]
        end

        subgraph "Models"
            Receipt["models/receipt.py<br/>VerificationReceipt"]
            Schemas["schemas.py<br/>LoanSchema and others"]
        end

        subgraph "Integrations"
            OR["integrations/open_responses.py"]
            UCP["integrations/ucp.py"]
        end

        subgraph "Core"
            FV["finance_verifier.py<br/>NPV, IRR, loans"]
        end
    end

    subgraph "Engines"
        Z3["Z3 SMT solver"]
        SymPy["SymPy"]
        MP["mpmath"]
        SQLGlot["SQLGlot"]
    end

    CG --> Z3
    FV --> SymPy
    DG --> MP
    QG --> SQLGlot

    XG --> CG
    XG --> MG
    XG --> QG
    XG --> Receipt
    OR --> Receipt
    UCP --> Receipt
```

## Verification flow

Every check follows the same path. Input that cannot be parsed, or that a check detects as ambiguous, fails closed: it is rejected, never passed through as if it were correct. Not every ambiguity is detected: cash flows that change sign more than once can have several IRRs (`[-100, 230, -132]` has roots at 10% and 20%), and `verify_irr` checks the claim against the first real root it finds instead of rejecting the input. Most guards return a rejected result; some methods raise instead (for example `verify_irr` raises `ValueError` for a claim that is not a number), so treat an exception from a guard as a rejection too.

```mermaid theme={null}
flowchart TD
    Call["Your code calls a guard<br/>with the model's output"] --> Parse{"Inputs parse and<br/>are within range?"}
    Parse -->|"no"| Reject["Rejected<br/>(fails closed)"]
    Parse -->|"yes"| Check["Recompute or check<br/>with the guard's engine"]
    Check --> Match{"Matches the model's claim<br/>or the rule?"}
    Match -->|"yes"| Pass["Verified"]
    Match -->|"no"| Fail["Rejected, with the computed<br/>value or the violations"]
```

`CrossGuard`, `UCPIntegration` and the built-in `OpenResponsesIntegration` tools also issue receipts. `UCPIntegration` can return `PENDING_REVIEW` when an amount needs an AML flag.

## Data flow

### Verification receipt

```mermaid theme={null}
flowchart LR
    subgraph Input
        LLM["Model output"]
    end

    subgraph Processing
        Hash["SHA-256<br/>input hash"]
        Guard["Guard<br/>check"]
        Proof["Proof steps"]
    end

    subgraph Output
        Receipt["Verification<br/>receipt"]
        Sig["HMAC-SHA256 signature<br/>(optional, your key)"]
        Log["Audit log"]
    end

    LLM --> Hash
    LLM --> Guard
    Guard --> Proof
    Hash --> Receipt
    Proof --> Receipt
    Receipt -.-> Sig
    Receipt --> Log
```

Receipts are unsigned until you call `get_signature(key)`. See [Compliance and auditing](/finance/compliance).

### Cross-guard pipeline: SWIFT with sanctions

`CrossGuard.verify_swift_with_sanctions()` runs three steps.

```mermaid theme={null}
flowchart TD
    Input["SWIFT MT103 message"]

    subgraph "Cross-guard pipeline"
        Step1["1. Message guard<br/>Validate the MT103 format"]
        Step2["2. Extract party names<br/>from the message"]
        Step3["3. Sanctions screening<br/>against the list you pass"]
    end

    Output1["Passed"]
    Output2["Sanctions hit"]
    Output3["Format error"]
    Output4["Unscreened: no sanctions list"]

    Input --> Step1
    Step1 -->|"valid"| Step2
    Step1 -->|"invalid"| Output3
    Step2 --> Step3
    Step3 -->|"clear"| Output1
    Step3 -->|"hit"| Output2
    Step3 -->|"empty or missing list"| Output4
```

An empty or missing sanctions list fails closed as unscreened. A name the screening cannot assess is sent to review, never cleared.

## Class diagram

```mermaid theme={null}
classDiagram
    class FinanceVerifier {
        +verify_npv(cashflows, rate, llm_output)
        +verify_irr(cashflows, llm_output)
        +verify_monthly_payment(principal, annual_rate, months, llm_output)
        +verify_total_interest(principal, annual_rate, months, llm_output)
        +verify_compound_interest(principal, rate, periods, llm_output, compounding)
    }

    class ComplianceGuard {
        -aml_thresholds: dict
        -high_risk_countries: set
        +verify_aml_flag(amount, country_code, llm_flagged)
        +verify_kyc_complete(has_id, has_address_proof, has_tax_id, llm_approved)
        +verify_sanctions_check(entity_name, is_on_sanctions_list, llm_approved)
        +verify_transaction_limit(amount, daily_limit, daily_total, llm_approved)
    }

    class MessageGuard {
        +verify_iso20022_xml(xml_string, msg_type)
        +verify_swift_mt(mt_string, mt_type)
        +verify_bic(bic, llm_says_valid)
        +verify_iban(iban, llm_says_valid)
    }

    class QueryGuard {
        -allowed_tables: Set
        +verify_readonly_safety(sql_query)
        +verify_table_access(sql_query, allowed_tables)
        +verify_column_access(sql_query, restricted_columns)
        +verify_no_injection(sql_query, user_input)
        +sanitize_query(sql_query)
    }

    class VerificationReceipt {
        +receipt_id: str
        +timestamp: str
        +input_hash: str
        +verified: bool
        +proof_steps: List
        +to_json()
        +get_signature(key)
    }

    class CrossGuard {
        -compliance: ComplianceGuard
        -message: MessageGuard
        -query: QueryGuard
        -audit_log: AuditLog
        +verify_swift_with_sanctions()
        +verify_iso20022_with_rules()
        +check_business_rules()
        +verify_query_with_pii_protection()
    }

    CrossGuard --> VerificationReceipt : generates
    CrossGuard --> ComplianceGuard : uses
    CrossGuard --> MessageGuard : uses
    CrossGuard --> QueryGuard : uses
```

## Deployment

* **Python:** install `qwed-finance` and call the guards from your service.
* **Node.js:** `@qwed-ai/finance` runs the Python package in a child process and passes JSON over stdin; install `qwed-finance` on the same machine. See the [Quickstart](/quickstart).
* **Receipts and audit logs:** `AuditLog` keeps receipts in memory. `export_json()` returns all of them as one JSON array, which suits reporting. To check receipts later, export each one with `to_json()` beside its signature, one pair per receipt, as shown in [Compliance and auditing](/finance/compliance).

***

## Design principles

### 1. Determinism first

The same input gives the same verdict. No sampling, no confidence scores.

### 2. Solvers and high precision over probability

Use solvers (Z3, SymPy) and high-precision arithmetic (mpmath, `Decimal`) instead of probabilistic confidence scores. The numerical checks run at a fixed, finite precision (30 decimal places for `DerivativesGuard`, 50 digits for `BondGuard`) and accept claims within a stated tolerance: they are repeatable, not exact symbolic answers. The IRR fallback reports `verification_mode="HEURISTIC"`.

### 3. Audit where it matters

`CrossGuard`, `UCPIntegration` and the built-in `OpenResponsesIntegration` tools generate receipts automatically. Direct guard calls and custom Open Responses tools return result objects; create a receipt with `ReceiptGenerator` when you need an audit record.

### 4. Fail closed

Input that is malformed, ambiguous or missing is rejected, never treated as passing.

***

## Related pages

* [Overview](/finance/overview): what QWED Finance checks
* [The 11 guards](/finance/guards): each guard with examples
* [Compliance and auditing](/finance/compliance): receipts and audit logs


## Related topics

- [Quickstart](/quickstart.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.