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

# QWED UCP guards for AI commerce verification

> Reference for QWED UCP guards including Money Guard, State Guard, Refund Guard, and Attestation Guard for AI commerce verification.

QWED-UCP includes **10 verification guards** that validate different aspects of UCP checkout data.

***

## 1. Money guard

**Verifies the total formula is mathematically correct.**

```
Total = Subtotal - Discount + Tax + Shipping + Fee
```

### Usage

```python theme={null}
driver = MoneyGuard()
result = driver.verify_cart_totals(
    line_items=[{"price": 35.00, "quantity": 2}, {"price": 15.00, "quantity": 1}],
    taxes=8.25,
    discounts=10.00,
    claimed_total=98.25
)
# Returns: {"verified": True}
```

### Tolerance

Uses `Decimal` precision with 1 cent (\$0.01) tolerance for floating-point errors.

***

## 2. State guard

**Verifies valid checkout state machine transitions.**

### Valid states

```
incomplete → ready_for_complete → completed
                              ↓
                            failed
                              ↓
                           cancelled
```

### Usage

```python theme={null}
from qwed_ucp.guards.state_guard import StateGuard

guard = StateGuard()
# Check if we can SHIP given the current state is PAID
result = guard.verify_transition(
    current_state="paid",
    action="ship"
)
# Returns: {"verified": True}
```

### Rules

* `incomplete`: Can be empty
* `ready_for_complete`: Must have line items
* `completed`: Must have order object
* Cannot transition backwards

***

## 3. Schema guard

**Validates UCP JSON schema compliance.**

### Usage

```python theme={null}
from qwed_ucp.guards import SchemaGuard

guard = SchemaGuard()
result = guard.verify(checkout_data)
```

### Validates

* Required fields present
* Correct types (string, number, array)
* Valid enum values (status, total types)

***

## 4. Line items guard

**Verifies price × quantity = line total for each item.**

### Usage

```python theme={null}
from qwed_ucp.guards import LineItemsGuard

guard = LineItemsGuard()
result = guard.verify({
    "line_items": [
        {"id": "roses", "quantity": 2, "item": {"price": 35.00}},
        {"id": "pot", "quantity": 1, "item": {"price": 15.00}}
    ],
    "totals": [{"type": "subtotal", "amount": 85.00}]  # 2×35 + 1×15 = 85 ✓
})
```

### Checks

* Each item: `price × quantity = line_total`
* Sum of line items = subtotal
* Quantities must be positive integers
* Prices must be non-negative

***

## 5. Discount guard

**Verifies percentage and fixed discount calculations.**

### Usage - percentage discount

```python theme={null}
from qwed_ucp.guards import DiscountGuard
from decimal import Decimal

guard = DiscountGuard()
result = guard.verify_percentage_discount(
    subtotal=Decimal("100.00"),
    discount_amount=Decimal("10.00"),
    percentage=Decimal("10")  # 10% of 100 = 10 ✓
)
```

### Usage - fixed discount

```python theme={null}
result = guard.verify_fixed_discount(
    subtotal=Decimal("50.00"),
    discount_amount=Decimal("5.00")  # Fixed $5 off ✓
)
```

### Rules

* Percentage: Must be 0-100%
* Fixed: Cannot exceed subtotal
* Discount must be non-negative

***

## 6. Currency guard

**Validates ISO 4217 currency codes and format.**

### Usage

```python theme={null}
from qwed_ucp.guards import CurrencyGuard

guard = CurrencyGuard()
result = guard.verify({"currency": "USD"})
```

### Validates

* 3-letter ISO 4217 codes (USD, EUR, GBP, JPY, etc.)
* Zero-decimal currencies (JPY, KRW) have no decimals
* Currency conversion accuracy

### Zero-decimal currencies

```python theme={null}
# Valid - no decimals
{"currency": "JPY", "totals": [{"type": "total", "amount": 1000}]}

# Invalid - JPY shouldn't have decimals
{"currency": "JPY", "totals": [{"type": "total", "amount": 1000.50}]}
```

***

## 7. Refund guard

**Verifies refund amounts match original transactions.**

### Usage - full refund

```python theme={null}
from qwed_ucp.guards.refund import RefundGuard
from decimal import Decimal

guard = RefundGuard()
result = guard.verify_full_refund(
    original_total=Decimal("100.00"),
    refund_amount=Decimal("100.00")
)
# Returns: RefundGuardResult(verified=True, details={"refund_type": "full"})
```

### Usage - partial refund

```python theme={null}
result = guard.verify_partial_refund(
    original_total=Decimal("100.00"),
    refund_amount=Decimal("50.00"),
    percentage=Decimal("50")  # 50% of 100 = 50 ✓
)
```

### Usage - tax reversal

```python theme={null}
result = guard.verify_tax_reversal(
    original_tax=Decimal("10.00"),
    refund_tax=Decimal("5.00"),
    refund_percentage=Decimal("50")  # 50% of tax reversed ✓
)
```

### Usage - checkout refund

```python theme={null}
checkout = {"totals": [{"type": "total", "amount": 100.00}]}
refund = {"amount": 100.00, "type": "full"}
result = guard.verify(checkout, refund)
```

### Rules

* Full refund must exactly match original total
* Partial refund percentage must be 0-100%
* Refund cannot exceed original total
* Tax reversal must be proportional to the refund percentage

***

## 8. Tip guard

**Verifies tip calculations (pre-tax and post-tax).**

### Usage - pre-tax tip

```python theme={null}
from qwed_ucp.guards.tip import TipGuard
from decimal import Decimal

guard = TipGuard()
result = guard.verify_percentage_tip(
    subtotal=Decimal("50.00"),
    tip_amount=Decimal("9.00"),
    percentage=Decimal("18")  # 18% of 50 = 9 ✓
)
# Returns: TipGuardResult(verified=True, details={"tip_type": "pre-tax"})
```

### Usage - post-tax tip

```python theme={null}
result = guard.verify_post_tax_tip(
    total=Decimal("108.00"),
    tip_amount=Decimal("21.60"),
    percentage=Decimal("20")  # 20% of 108 = 21.60 ✓
)
# Returns: TipGuardResult(verified=True, details={"tip_type": "post-tax"})
```

### Usage - bounds check

```python theme={null}
result = guard.verify_tip_bounds(
    tip_amount=Decimal("20.00"),
    base_amount=Decimal("100.00")
)
```

### Rules

* Tip percentage must be 0-100%
* Tip cannot be negative
* Tip cannot exceed 100% of the base amount
* Supports both pre-tax (subtotal) and post-tax (total) calculations

***

## 9. Fee guard

**Verifies fee calculations (service, delivery, platform).**

### Usage - service fee

```python theme={null}
from qwed_ucp.guards.fee import FeeGuard
from decimal import Decimal

guard = FeeGuard()
result = guard.verify_service_fee(
    subtotal=Decimal("100.00"),
    fee_amount=Decimal("5.00"),
    percentage=Decimal("5")  # 5% of 100 = 5 ✓
)
# Returns: FeeGuardResult(verified=True, details={"fee_type": "service"})
```

### Usage - delivery fee

```python theme={null}
# Formula: base_fee + (distance × rate_per_km)
result = guard.verify_delivery_fee(
    claimed_fee=Decimal("13.00"),
    distance_km=Decimal("5"),
    rate_per_km=Decimal("2.00"),
    base_fee=Decimal("3.00")  # 3 + 5×2 = 13 ✓
)
# Returns: FeeGuardResult(verified=True, details={"fee_type": "delivery"})
```

### Usage - platform fee

```python theme={null}
result = guard.verify_platform_fee(
    fee_amount=Decimal("15.00"),
    subtotal=Decimal("100.00"),
    max_percentage=Decimal("30")  # 15% < 30% max ✓
)
```

### Rules

* Fee percentage cannot be negative
* Distance and rate cannot be negative
* Platform fee cannot be negative
* Platform fee cannot exceed the configured maximum percentage (default 30%)

***

## 10. Attestation guard

**Generates cryptographic proofs (JWTs) for verification results.**

### Usage - sign a checkout

Every attestation is bound to a **single verification event**. You must pass a unique `transaction_attempt_id` and a one-time `request_nonce` when signing — the same values must be supplied at verify time. This prevents an attestation from one checkout being replayed against another.

```python theme={null}
import uuid
from qwed_ucp import UCPVerifier
from qwed_ucp.guards.attestation import AttestationGuard

# Production: provide a secret key or set QWED_ATTESTATION_SECRET env var
guard = AttestationGuard(secret_key="your-secret-key")

# Dev mode: use allow_insecure=True (generates a random secret)
guard = AttestationGuard(allow_insecure=True)

# Bindings for this verification event
transaction_attempt_id = str(uuid.uuid4())
request_nonce = str(uuid.uuid4())

# You can pass a UCPVerificationResult directly — no need to convert to a dict
checkout = {"currency": "USD", "totals": [{"type": "total", "amount": 82.79}]}
verifier = UCPVerifier()
verification = verifier.verify_checkout(checkout)

signed = guard.sign_checkout(
    checkout=checkout,
    verification_result=verification,
    guards_passed=[g.guard_name for g in verification.guards if g.verified],
    transaction_attempt_id=transaction_attempt_id,
    request_nonce=request_nonce,
    session_id="sess_abc123",       # optional
    merchant_id="merchant_42",       # optional
)

print(signed.token)                              # JWT token string
print(signed.verified)                          # True on success
print(signed.details["attestation_id"])          # UUID — matches JWT `jti`
print(signed.details["checkout_hash"])           # SHA-256 of checkout
```

<Note>
  `verification_result` accepts either a `UCPVerificationResult` returned by `UCPVerifier.verify_checkout(...)` or a legacy `{"verified": bool, "errors": [...]}` dict. Both are normalized internally.
</Note>

### Usage - verify an attestation

Verification is fail-closed on binding mismatch. You must pass the same `transaction_attempt_id` and `request_nonce` used when signing; any mismatch — or a missing `jti`, or a token that has already been consumed — returns `verified=False`.

```python theme={null}
result = guard.verify_attestation(
    token="eyJ...",
    expected_transaction_attempt_id=transaction_attempt_id,
    expected_request_nonce=request_nonce,
    expected_session_id="sess_abc123",   # optional, enforced if provided
    expected_merchant_id="merchant_42",   # optional, enforced if provided
    consume=True,                         # mark token consumed to prevent replay
)

print(result.verified)  # True if valid, unexpired, bindings match, not consumed
print(result.details)   # Decoded JWT payload
```

<Warning>
  Attestations are single-use by default. When `consume=True` (the default), the guard records the JWT's `jti` and rejects any later call that presents the same token. Set `consume=False` only for read-only inspection.
</Warning>

### Usage - create a receipt

`create_receipt` produces a non-cryptographic audit summary that pairs with an attestation. The `attestation_id` should be the same UUID returned in `sign_checkout(...).details["attestation_id"]`, and `transaction_attempt_id` must match the value bound into the JWT.

```python theme={null}
receipt = guard.create_receipt(
    checkout=checkout,
    verification_result=verification,
    attestation_id=signed.details["attestation_id"],
    transaction_attempt_id=transaction_attempt_id,
    previous_receipt_id=None,   # optional predecessor for audit chains
)

print(receipt["receipt_id"])              # "QWED-<attestation-id-uppercase>"
print(receipt["attestation_id"])          # Matches the JWT `jti`
print(receipt["transaction_attempt_id"])  # Same value passed to sign_checkout
print(receipt["verified"])                # True
print(receipt["engine"])                  # "QWED-Deterministic-v1"
```

### JWT payload fields

| Field                     | Type               | Description                                                    |
| ------------------------- | ------------------ | -------------------------------------------------------------- |
| `iss`                     | `string`           | Always `"qwed-ucp-attestation"`                                |
| `jti`                     | `string`           | Unique attestation ID (UUID) — used for single-use enforcement |
| `iat`                     | `int`              | Issued-at Unix timestamp                                       |
| `exp`                     | `int`              | Expiration timestamp (1 hour after issuance)                   |
| `checkout_hash`           | `string`           | SHA-256 hash of the checkout object                            |
| `transaction_attempt_id`  | `string`           | Verification attempt binding (required)                        |
| `request_nonce`           | `string`           | One-time nonce for this verification event (required)          |
| `session_id`              | `string` \| `null` | Optional session binding, enforced at verify time when set     |
| `merchant_id`             | `string` \| `null` | Optional merchant binding, enforced at verify time when set    |
| `previous_attestation_id` | `string` \| `null` | Optional predecessor for audit chains                          |
| `verified`                | `bool`             | Whether the checkout passed verification                       |
| `guards_passed`           | `array`            | List of guard names that passed                                |
| `errors`                  | `array`            | List of errors (if any)                                        |
| `engine`                  | `string`           | `"QWED-Deterministic-v1"`                                      |
| `verification_mode`       | `string`           | `"deterministic"`                                              |

<Warning>
  In production, set `QWED_ATTESTATION_SECRET` as an environment variable or pass `secret_key` directly. Without a secret, initialization raises a `ValueError` unless `allow_insecure=True` or the `QWED_DEV_MODE=1` env var is set.
</Warning>

***

## Verification result fields

All guard results and `UCPVerificationResult` include:

| Field               | Type          | Description                                                          |
| ------------------- | ------------- | -------------------------------------------------------------------- |
| `verified`          | `bool`        | Convenience flag — `True` only when `status == TrustStatus.VERIFIED` |
| `status`            | `TrustStatus` | Typed trust verdict — see [Trust status](#trust-status) below        |
| `engine`            | `string`      | `"QWED-Deterministic-v1"`                                            |
| `verification_mode` | `string`      | `"deterministic"`                                                    |
| `error`             | `string`      | Error message (when `verified` is `false`)                           |

***

## Trust status

Every guard result and `UCPVerificationResult` carries a typed `status: TrustStatus` field that distinguishes between materially different failure modes. The `TrustStatus` enum is available from `qwed-ucp` v0.3.0 onward. Downstream policy code should branch on `status` rather than the derived `verified: bool`, so that "proof disproved" is not treated the same as "verifier engine crashed."

### States

| State          | When it's used                                                     |
| -------------- | ------------------------------------------------------------------ |
| `VERIFIED`     | Deterministic proof succeeded under supported conditions.          |
| `FAILED`       | Proof was attempted and disproved (for example, totals mismatch).  |
| `UNVERIFIABLE` | Proof could not be established (for example, missing proof basis). |
| `UNSUPPORTED`  | Input or state is outside supported semantics.                     |
| `PARTIAL`      | Some checks ran, but no final verdict is justified.                |
| `ENGINE_ERROR` | A verifier dependency or the runtime crashed or degraded.          |
| `QUARANTINED`  | Reserved for policy-level rejection (not yet wired).               |

### Reading `status`

```python theme={null}
from qwed_ucp import UCPVerifier, TrustStatus

verifier = UCPVerifier()
result = verifier.verify_checkout(checkout_data)

if result.status == TrustStatus.VERIFIED:
    # Safe to proceed to payment
    ...
elif result.status == TrustStatus.FAILED:
    # A guard deterministically disproved the transaction
    return reject(reason="proof_failed", errors=result.errors)
elif result.status == TrustStatus.ENGINE_ERROR:
    # A guard raised an exception — fail closed and page an operator
    return reject(reason="verifier_unavailable")
else:
    # UNVERIFIABLE / UNSUPPORTED / PARTIAL — treat as untrusted
    return reject(reason=str(result.status))
```

### Verifier-level aggregation

`UCPVerifier.verify_checkout()` propagates the most-severe guard status to the top-level result (fail-closed ordering):

| Top-level status | When it's used                                                                 |
| ---------------- | ------------------------------------------------------------------------------ |
| `ENGINE_ERROR`   | Any guard raised an exception during verification.                             |
| `QUARANTINED`    | A guard returned `QUARANTINED` (reserved for policy-level rejection).          |
| `FAILED`         | A guard deterministically disproved the transaction.                           |
| `UNVERIFIABLE`   | Most-severe guard status is `UNVERIFIABLE` (e.g. missing proof basis).         |
| `UNSUPPORTED`    | Most-severe guard status is `UNSUPPORTED` (input outside supported semantics). |
| `PARTIAL`        | Most-severe guard status is `PARTIAL` (inconclusive checks).                   |
| `VERIFIED`       | All guards passed (`VERIFIED`).                                                |

<Note>
  `verified: bool` remains a backward-compatible derived field: `result.verified` is `True` only when `result.status == TrustStatus.VERIFIED`. Existing code that reads `result.verified` continues to work unchanged, and existing constructors that pass `verified=True` or `verified=False` still produce the corresponding `VERIFIED` or `FAILED` status.
</Note>

***

## Running all guards

Use `UCPVerifier` to run all guards at once:

```python theme={null}
from qwed_ucp import UCPVerifier, TrustStatus

verifier = UCPVerifier()
result = verifier.verify_checkout(checkout_data)

print(f"Verified: {result.verified}")
print(f"Status: {result.status}")                      # TrustStatus.VERIFIED
print(f"Engine: {result.engine}")                     # "QWED-Deterministic-v1"
print(f"Mode: {result.verification_mode}")             # "deterministic"
print(f"Guards passed: {len([g for g in result.guards if g.status == TrustStatus.VERIFIED])}")
```
