# RAG diagnostics

`com.tnsai.intelligence.rag.binding.RagDiagnostics` is `@since 0.15.0`
(`TnsAI@32e17445`,
[PR #199](https://github.com/TnsAI-Framework/TnsAI/pull/199) /
[TAN-5888](https://linear.app/tansuasici-workspace-1/issue/TAN-5888)).
It ships in `0.15.0` and later — see
[Installation](../../start/installation.md) for the coordinates.

R5's four code items are one sentence: a RAG downgrade is visible.
`RagDiagnostics` is the pull half of that sentence — you can ask what a
Role's declarations actually resolved to before a bad answer costs a
debugging session.

## What it does

The snapshot answers the questions the binding already computed and
used to hide:

- which `EmbeddingFunction` is in use, and whether it is the bundled
  hash fallback
- whether a reranker, query expander, or graph-store provider is
  installed — absence is a reported fact, not an exception
- per source: name, type, detected format, document count, chunk count,
  and ingest fingerprint
- the effective `@Retrieval` configuration after resolution

It does not change retrieval behaviour. It is not an annotation, not a
log line, and not telemetry. You ask; the framework answers.

## How to ask

`RagDiagnostics.of(roleType)` never ingests. It snapshots a binding
that already exists for that Role class. If nothing has been built yet,
use the explicit flag: `RagDiagnostics.of(roleType, true)` constructs
the binding (and therefore runs ingest).

`report()` returns unstable human-readable text. Paste it into an
issue; do not parse it. Typed accessors on the snapshot are the
supported surface for tests and health checks.

<!-- java-contract: src/main/java/com/example/tnsai/docs/RagDiagnosticsExample.java -->
```java
package com.example.tnsai.docs;

import com.tnsai.annotations.ActionSpec;
import com.tnsai.annotations.KnowledgeSource;
import com.tnsai.annotations.Retrieval;
import com.tnsai.enums.ActionType;
import com.tnsai.intelligence.rag.binding.RagDiagnostics;
import com.tnsai.models.role.RoleIdentity;
import com.tnsai.roles.Role;

public final class RagDiagnosticsExample {
    private RagDiagnosticsExample() {}

    @KnowledgeSource(
        name = "product-docs",
        type = KnowledgeSource.KnowledgeType.FILE,
        path = "knowledge/products")
    @Retrieval(
        strategy = Retrieval.Strategy.SEMANTIC,
        sources = "product-docs",
        queryParam = "question",
        topK = 5)
    public static final class FaqRole extends Role {
        @Override
        public RoleIdentity getIdentity() {
            return new RoleIdentity("faq", "FAQ answers", "support");
        }

        @ActionSpec(
            type = ActionType.LLM,
            description = "Answer from product documentation")
        public String answer(String question) {
            return question;
        }
    }

    public static String inspectExistingBinding() {
        return RagDiagnostics.of(FaqRole.class).report();
    }

    public static String inspectByBuilding() {
        return RagDiagnostics.of(FaqRole.class, true).report();
    }
}
```

`inspectExistingBinding()` is the cheap question: what did this Role
already become? `inspectByBuilding()` is the explicit "build it so I
can see it" path. Do not call the two-argument form from a health
endpoint unless you intend to pay ingest.

## Four silent downgrades, now visible

These four used to fail as *plausible but worse answers*. They now
surface as a warning, a named exception, a startup configuration
error, or a diagnostic you can ask.

### Hash embedding fallback

No installed `EmbeddingFunction` plus a vector-backed `@Retrieval`
strategy used to rank by token overlap with no log line. Framework
main (`TnsAI@89d41d1b`,
[PR #195](https://github.com/TnsAI-Framework/TnsAI/pull/195) /
[TAN-5885](https://linear.app/tansuasici-workspace-1/issue/TAN-5885))
emits one process-lifetime WARN per Role class when `SEMANTIC`,
`HYBRID`, `HIERARCHICAL`, or `TEMPORAL` resolve to the bundled hash
embedding. `KEYWORD`, `GRAPH`, `REASONING`, and `MULTI_QUERY` stay
silent on this path. The fallback still runs — the defect was the
silence.

What you see, what it means, and what to do:
[Embeddings — hash-embedding fallback](embeddings.md#hash-embedding-fallback-0150).

`RagDiagnostics` distinguishes the fallback case from an installed
provider without throwing.

### Absent expander and reranker messages

TnsAI ships no bundled `Reranker` and no bundled `QueryExpander`.
`RerankerRegistry` already named the cause, the registered providers,
and two remedies. `QueryExpanderRegistry` used to throw only
"No QueryExpander provider supports mode … and model '…'".

TnsAI `0.15.0` (`TnsAI` [PR #197](https://github.com/TnsAI-Framework/TnsAI/pull/197) /
[TAN-5886](https://linear.app/tansuasici-workspace-1/issue/TAN-5886))
brings the expander message to the same skeleton: registered
providers, that TnsAI ships no built-in expander, and a remedy that
matches the `(strategy, queryExpansion)` pair — not a copy-pasted
`queryExpansion = NONE` on every shape.

`RagDiagnostics` reports installed or absent status for both seams
without throwing. Use that when you want the fact before the first
query; use the exception message when a query already failed.

### Eager reranker and expander validation

On Maven Central `0.14.1`, a typo in `rerankerModel` or
`queryExpansionModel` compiles, starts, and throws on the first query
— inside the span `@Retrieval.onFailure` guards. `CONTINUE` can then
emit an ungrounded answer. `GRAPH` already refused that shape: which
provider can serve the annotation is fixed by the classpath, never by
request data.

TnsAI `0.15.0` (`TnsAI@cb14410d`,
[PR #198](https://github.com/TnsAI-Framework/TnsAI/pull/198) /
[TAN-5887](https://linear.app/tansuasici-workspace-1/issue/TAN-5887))
resolves those two model names when `Role.create` establishes the
retrieval configuration. An unservable name is a wiring-time
configuration error, above `onFailure`. Failures a provider raises
*while* ranking or expanding still follow `onFailure`.

Roles with no effective `@Retrieval`, and declarations that do not
ask for rerank or expansion, do not load those provider graphs.

See [Annotation runtime status](../../reference/annotations/runtime-status.md).

### Inspectability

The three fixes above announce a problem. `RagDiagnostics` is the
positive case: everything resolved, here is what you got — including
corpus counts and the ingest fingerprint — plus the fallback bit you
can assert in a test.

## Not this page

- A new annotation or automatic dump at startup
- A metrics or time-series surface for ingest
- Maven Central `0.14.1` behaviour — this type does not exist there
- How to install an `EmbeddingFunction` provider — see
  [Strategies](strategies.md#tnsai-0140-declarative-embedding-provider)

## Related

- [Embeddings](embeddings.md) — hash-fallback warning and Matryoshka prefixes
- [Strategies](strategies.md) — declarative embedding provider SPI
- [Declarative RAG](index.md) — `@KnowledgeSource` / `@Retrieval` fields
- [Annotation runtime status](../../reference/annotations/runtime-status.md) — wiring vs dispatch
