---
title: "XRAG: Verified-Provenance RAG"
description: "How XI Lucent integrates XION cryptographic trust verification into the ingestion path, what attribution metadata looks like on chunks, and how signed sources are preserved for independent re-verification."
published: 2026-05-14T12:11:25.651189+00:00
updated: 2026-05-14T12:11:25.651189+00:00
tags: ["concepts", "lucent", "provenance", "xion", "xrag"]
url: https://xiobjects.com/docs/xio/lucent/concepts/xrag
source: XI Objects
---

<!-- xion:doctype xion+markdown -->
<!-- xion:metadata
{
  "version": "1.0",
  "content_type": "application/xion\u002Bmarkdown",
  "source_type": "xi-content/doc",
  "generator": "xio-content-publisher/1.0.0",
  "generated": "2026-05-14T12:10:19.5899743\u002B00:00",
  "encoding": "utf-8",
  "render_intent": "markdown",
  "title": "XRAG: Verified-Provenance RAG",
  "slug": "xio/lucent/concepts/xrag",
  "copyright": "\u00A9 2026 XI Objects Inc"
}
-->

# XRAG: Verified-Provenance RAG

Standard RAG systems have no way to know whether the documents they've ingested are authentic, unmodified, or from who they claim to be from. XRAG addresses this by running XION cryptographic verification as a pre-flight step in the ingestion pipeline. If verification fails, the document is rejected before chunking even starts. If it passes, the signer's identity travels with every chunk produced from that document.

XRAG was introduced in Lucent 1.2.0. Signed source preservation was added in 1.3.0.

## How verification works at ingest time

When `AddDocumentRequest.IsXionContent = true`, the ingestion pipeline hands the raw bytes to `IXionDocumentProcessor` before any other stage. The processor:

1. Verifies the BLAKE3 content hash against the embedded trust block
2. Validates the Ed25519 signature with the embedded public key
3. Confirms the certificate chain traces to the Institute of Provenance Root CA
4. Checks that no certificate in the chain has been revoked
5. Strips the `xion:doctype`, `xion:metadata`, and `xion:trust` blocks from the payload
6. Returns the canonical body for the rest of the pipeline to process normally

```mermaid
flowchart LR
    A[Signed XION document] --> B{XION Verification}
    B -- Fail --> C[HTTP 422 / FailedPrecondition]
    B -- Pass --> D[Strip trust blocks]
    D --> E[Canonical body]
    E --> F[Detection → Chunking → Embedding]

    style A fill:#1a1a2e,stroke:#7a4a9e,color:#e1d5b9
    style B fill:#582c7e,stroke:#7a4a9e,color:#fff
    style C fill:#0a0e1a,stroke:#ff3a00,color:#e1d5b9
    style D fill:#1a1a2e,stroke:#7a4a9e,color:#e1d5b9
    style E fill:#1a1a2e,stroke:#7a4a9e,color:#e1d5b9
    style F fill:#1a1a2e,stroke:#7a4a9e,color:#e1d5b9
```

Verification is strict: any failure is a hard rejection. There's no "unverified but ingested anyway" path.

## Enabling XRAG

```csharp
services.AddLucent(opts => { /* adapters */ })
        .AddLucentXionVerification(pki =>
        {
            pki.RootsPemPath = "/etc/xio/pki/roots.pem";
        });
```

Without calling `AddLucentXionVerification`, setting `IsXionContent = true` will throw at runtime. This is intentional: XRAG requires explicit PKI configuration.

## Attribution on chunks

When ingestion succeeds, every chunk produced from the document carries a `XionAttribution` record on its `ChunkMetadata`:

```json
{
  "attribution": {
    "keyId": "uH1O2KWkOIBYXvCfRbWphkGQdfAH6Ggx2GkjYih--O0",
    "trustHashHex": "6834d38d07b76822f32a88b35fddc377401f556bff0a6df32f8f191695dafbc8",
    "context": "xio.devcenter.testrunner",
    "signedAt": "2026-04-19T14:20:29+00:00",
    "x509LeafThumbprint": "3f8a…",
    "doctype": "xion+markdown",
    "metadata": {
      "project_id": "prj-lucient",
      "task_id": "39e66bba52a9"
    }
  }
}
```

| Field | Meaning |
|-------|---------|
| `keyId` | Signer's public key fingerprint |
| `trustHashHex` | BLAKE3 hash of the canonical document |
| `context` | Trust context string from the `xion:trust` block |
| `signedAt` | Signing timestamp from the trust block |
| `x509LeafThumbprint` | SHA-1 of the signer's leaf X.509 certificate |
| `doctype` | XION document type (e.g. `xion+markdown`) |
| `metadata` | Flattened `xion:metadata` fields |

This attribution is queryable via filter expressions. You can retrieve all chunks signed by a particular key, from a specific context, or within a date range:

```csharp
using static Lucent.Filter;

var result = await engine.QueryAsync("docs", new QueryRequest
{
    Text = "authentication requirements",
    Filter = And(
        Eq("attr_kid", "uH1O2KWkOIBYXvCfRbWphkGQdfAH6Ggx2GkjYih--O0"),
        Eq("attr_context", "xio.devcenter.testrunner")
    )
});
```

## Mixed collections

Not every document in a collection needs to be XION-signed. Non-XION documents work exactly as they do without XRAG enabled. Chunks from non-XION documents simply have no `attribution` field. You can query across the whole collection and inspect `hit.Chunk.Metadata.Attribution` to distinguish verified from unverified chunks.

## Signed source preservation

From 1.3.0, Lucent preserves the original signed bytes for every XION document, including the raw trust block. This lets you reconstruct and independently re-verify a document at any point after ingestion.

```csharp
using var sink = new MemoryStream();
var present = await engine.GetSignedSourceAsync(collectionId, documentId, sink, ct);
if (!present)
    throw new Exception("not a XION document");

// Re-verify independently — no Lucent in the loop
var raw = Encoding.UTF8.GetString(sink.ToArray());
var verificationResult = await independentVerifier.VerifyAsync(raw, ct);
if (!verificationResult.IsVerified)
    throw new Exception(verificationResult.ErrorMessage);
```

`GetSignedSourceAsync` returns `false` for documents that weren't ingested as XION content. The preserved bytes include the original trust block, so the resulting document is a complete XION artifact that any compliant verifier can check.

The signed source is accessible over all control surfaces:
- HTTP: `GET /v1/collections/{id}/documents/{docId}/signed-source` (streams the bytes; returns 404 for non-XION)
- gRPC: `GetSignedSource` RPC (server-streaming, 64 KiB frames)
- MCP: `lucent_get_signed_source` tool (returns base64-encoded bytes)
- CLI: `xio-lucent docs source <collection> <docId> -o restored.xion.md`

## SQLite schema

Attribution fields are stored in both the `chunks` and `documents` tables. Two indices accelerate attribution-keyed queries:

- `idx_chunks_attr_kid ON chunks(attr_kid)` — queries by signer key ID
- `idx_chunks_attr_leaf ON chunks(attr_leaf_thumb)` — queries by certificate thumbprint

The signed source BLOB (`signed_source`) and raw trust block JSON (`attr_trust_json`) live on the `documents` table only. Per-chunk storage of the full XION bytes would be prohibitively large for documents with many chunks.

The schema is versioned (v1 → v2 → v3). Migrations are idempotent and non-destructive; existing databases upgrade automatically on first use.
<!-- xion:trust
{
  "v": 1,
  "canon_v": 1,
  "ctx": "xiobjects.com/content",
  "hash_blake3_hex": "82a5b970dff65436f8d457da57b2a4efe250e4aa4dc34f07e7e0c970f1cfac56",
  "hash_sha256_hex": null,
  "sig_alg": "ed25519",
  "sig_b64": "iPx1St6X5WP1UDnO3hL6VVcI-Rri4-ma8daThH-S8FGaozbziEqA5ZPVV-pR4qfoDSrp2XrfwKlpefxm0OxSAw",
  "pubkey_b64": "h-awvV8Rn-juph_c2Y7UH5A6e7NaFia3zBiMrJUOMOo",
  "x509_chain_pem": [
    "-----BEGIN CERTIFICATE-----\r\nMIIB9DCCAaagAwIBAgIQBrrNsmRlBvKQdA4idEliJjAFBgMrZXAwLjEsMCoGA1UE\r\nAwwjWEkgT2JqZWN0cyBJbmMgQ29udHJvbCBJbnRlcm1lZGlhdGUwHhcNMjYwNTEz\r\nMjI0NjA1WhcNMjYwNjEyMjI0NjA1WjBLMR4wHAYDVQQDDBV4aW8tY29udGVudC1w\r\ndWJsaXNoZXIxFzAVBgNVBAoMDlhJIE9iamVjdHMgSW5jMRAwDgYDVQQLDAdDb250\r\nZW50MCowBQYDK2VwAyEAh\u002BawvV8Rn\u002Bjuph/c2Y7UH5A6e7NaFia3zBiMrJUOMOqj\r\ngbwwgbkwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYI\r\nKwYBBQUHAyQwZQYDVR0jBF4wXIAUOym3mFmw/qs1fgKrujCkxhrTk7KhLqQsMCox\r\nKDAmBgNVBAMMH0luc3RpdHV0ZSBvZiBQcm92ZW5hbmNlIFJvb3QgQ0GCFFJgN/ix\r\nQn72H6h3T5lEr9f8lJQFMB0GA1UdDgQWBBS1LSJi5\u002BeqBq8h974Ht9HTgIcdgTAF\r\nBgMrZXADQQCKjXbPwnk/DZHmLQstUWRzU6GSf\u002BSHTXTTZCtRLbmJKxT17Qlbpexc\r\nsRgdSpxNWpJPe9Fr4vwhRkESMqMIpgQO\r\n-----END CERTIFICATE-----\r\n",
    "-----BEGIN CERTIFICATE-----\r\nMIIByDCCAXqgAwIBAgIUUmA3\u002BLFCfvYfqHdPmUSv1/yUlAUwBQYDK2VwMCoxKDAm\r\nBgNVBAMMH0luc3RpdHV0ZSBvZiBQcm92ZW5hbmNlIFJvb3QgQ0EwHhcNMjUxMTAy\r\nMDMxNzEyWhcNMzAxMTAxMDMxNzEyWjAuMSwwKgYDVQQDDCNYSSBPYmplY3RzIElu\r\nYyBDb250cm9sIEludGVybWVkaWF0ZTAqMAUGAytlcAMhAFSS/pggSRmTcAMko7uc\r\nATH8OHgxVymd5mBFlPXbJkgio4GtMIGqMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYD\r\nVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQ7KbeYWbD\u002BqzV\u002BAqu6MKTGGtOTsjBlBgNV\r\nHSMEXjBcgBQAZRTDswSVORu\u002BkUOKX6WvrOvmQKEupCwwKjEoMCYGA1UEAwwfSW5z\r\ndGl0dXRlIG9mIFByb3ZlbmFuY2UgUm9vdCBDQYIUJqoJlpiSFg\u002B7W5IJLMrLttgR\r\nQp4wBQYDK2VwA0EA5FOht7YOsVRPp/FOKMQ\u002B3Mo9JxrvGR3ylKWAWNm6OUV7N3DB\r\nI9cD62wU5I0d0EKDBy0CX9DnoqUyxv5yguraAA==\r\n-----END CERTIFICATE-----\r\n",
    "-----BEGIN CERTIFICATE-----\r\nMIIBaTCCARugAwIBAgIUJqoJlpiSFg\u002B7W5IJLMrLttgRQp4wBQYDK2VwMCoxKDAm\r\nBgNVBAMMH0luc3RpdHV0ZSBvZiBQcm92ZW5hbmNlIFJvb3QgQ0EwHhcNMjUxMTAy\r\nMDMwNTEyWhcNMzUxMDMxMDMwNTEyWjAqMSgwJgYDVQQDDB9JbnN0aXR1dGUgb2Yg\r\nUHJvdmVuYW5jZSBSb290IENBMCowBQYDK2VwAyEAEWNZl\u002Br3IC7\u002BgBh90Yo1kWk1\r\npZCVzVuFdFT7qBBU8W2jUzBRMB0GA1UdDgQWBBQAZRTDswSVORu\u002BkUOKX6WvrOvm\r\nQDAfBgNVHSMEGDAWgBQAZRTDswSVORu\u002BkUOKX6WvrOvmQDAPBgNVHRMBAf8EBTAD\r\nAQH/MAUGAytlcANBAO6QeydOFNrN75qNyftggYudsxMyl4w9qWkSdZ6hlhrRcbSr\r\niG9Si0kbrIJOwYB/LTBU0RM4Rl\u002Bo9PM3Qp0mPwo=\r\n-----END CERTIFICATE-----\r\n"
  ],
  "key_id": "SDyVO7FvlAM-6CvQ62VZYOBO7JADFqLquUunUABRgKg",
  "created_at": "2026-05-14T12:10:19Z"
}
-->