{% extends "base.html" %} {% from "_page_header.html" import page_header %} {% from "_components.html" import badge, field %} {% block content %} {{ page_header("Query Lab", "Run a query through the production retrieval pipeline and see why each chunk was found and why it ranks where it does: authorization, dense and sparse candidates, RRF fusion, context assembly, answerability and per-stage timings. Scores are ranking signals, not probabilities.") }}

Query

{% if form_error %} {% endif %} {% if not catalog.available %}

Selector lists could not be loaded from the control plane; use the Advanced fields below to target spaces, sources or documents by ID.

{% endif %}
{% call field("query", "Query text") %} {% endcall %}
{% call field("profile", "Retrieval profile") %} {% endcall %} {% call field("max_results", "Max results") %} {% endcall %}
{% call field("space_ids", "Knowledge spaces", "Only spaces you are granted are ever searched; leave empty for all granted spaces.") %} {% endcall %} {% call field("source_ids", "Sources", "Restrict to documents of these sources.") %} {% endcall %} {% call field("document_ids", "Documents", ("Most recent " ~ (catalog.documents | length) ~ " documents shown; use Advanced for others.") if catalog.truncated_documents else "Restrict to specific documents.") %} {% endcall %}
{% call field("languages", "Languages") %} {% endcall %} {% call field("content_types", "Content types") %} {% endcall %} {% call field("trust_levels", "Trust levels") %} {% endcall %}
Advanced: raw identifiers

Comma-separated UUIDs, merged with the selections above. Every filter is applied server-side by the same filter compiler /v1/search uses.

{% call field("requested_space_ids", "Knowledge-space IDs") %} {% endcall %} {% call field("raw_source_ids", "Source IDs") %} {% endcall %} {% call field("raw_document_ids", "Document IDs") %} {% endcall %}

Retrieval inspector

{% if trace is none %}

Run a query above to inspect the retrieval pipeline.

{% else %} {#- Summary -#}

Answerability

{{ badge(trace.answerability.status | replace("_", " "), "ok" if trace.answerability.status == "answerable" else ("warn" if trace.answerability.status in ("partially_answerable", "conflicting_evidence") else "neutral")) }}

Evidence count

{{ trace.answerability.evidence_count }}

Candidates

{{ trace.dense_candidates | length }} dense · {{ trace.sparse_candidates | length }} sparse

Fused

{{ trace.fusion.candidates | length }}{% if trace.fusion.suppressed_count %} ({{ trace.fusion.suppressed_count }} suppressed){% endif %}

Degraded

{{ badge("Yes", "error") if trace.degraded else badge("No", "ok") }}

Latency

{{ "%.1f" | format(trace.timings_ms.values() | sum) }} ms

profile {{ trace.profile }}

{% if trace.degraded %} {% endif %} {% if not trace.fusion.candidates and not trace.degraded %}

Zero results: no published chunk in the effective spaces matched the query and filters.

{% endif %} {#- Authorization & filters -#}
Effective authorization & filters

Requested spaces: {{ trace.effective_filters.requested_space_ids | join(", ") or "all granted" }}

Effective spaces (server-computed): {{ trace.effective_filters.effective_space_ids | join(", ") or "none" }}

Denied / not granted: {{ trace.effective_filters.denied_space_ids | join(", ") or "none" }}

Trust-required spaces: {{ trace.effective_filters.trust_required_space_ids | join(", ") or "none" }}

Content types applied: {{ trace.effective_filters.applied_content_types | join(", ") or "none" }}

Languages applied: {{ trace.effective_filters.applied_languages | join(", ") or "none" }}

Source, document and trust-level filters are applied server-side in the same Qdrant filter as the space scope.

{#- Candidates -#}
Candidates — dense ({{ trace.dense_candidates | length }})
{% set candidate_list = trace.dense_candidates %}{% set fused = false %} {% include "query_lab/_candidate_table.html" %}
Candidates — sparse ({{ trace.sparse_candidates | length }})
{% set candidate_list = trace.sparse_candidates %}{% set fused = false %} {% include "query_lab/_candidate_table.html" %}
{#- Fusion -#}
Fusion — RRF ranking ({{ trace.fusion.candidates | length }}{% if trace.fusion.suppressed_count %}, {{ trace.fusion.suppressed_count }} suppressed as duplicate or over the per-document cap{% endif %})

RRF score = Σ 1 / (k + rank) over the backends that returned the chunk. A chunk found by both backends outranks one found by only one at the same rank. This fused order is the real ranking: no reranker is active in this deployment.

{% set candidate_list = trace.fusion.candidates %}{% set fused = true %} {% include "query_lab/_candidate_table.html" %}
{% if rerank_active %}
Reranking ({{ trace.rerank.state }})
{% if trace.rerank.degradation_code %}

Degradation code: {{ trace.rerank.degradation_code }}

{% endif %} {% set candidate_list = trace.rerank.candidates %}{% set fused = false %} {% include "query_lab/_candidate_table.html" %}
{% endif %} {#- Context -#}
Context — assembly & parent expansion

Token budget: {{ trace.context.token_count }} / {{ trace.context.max_context_tokens }} · Blocks: {{ trace.context.block_count }} · Citations in context: {{ trace.context.citation_ids | length }}

Parent expansions applied: {{ trace.parent_expansion.expanded_count }} · Skipped: {{ trace.parent_expansion.skipped_count }} · Expansion tokens: {{ trace.parent_expansion.total_expansion_tokens }}

{% for citation in trace.citations %} {% else %} {% endfor %}
Citations included in the final context
Provenance Excerpt

{{ citation.display or citation.document_title or ("Document " ~ (citation.document_id | string)[:8] ~ "…") }}

{% if citation.source_name %}{{ citation.source_name }} · {% endif %}{{ citation.source_uri }}

doc {{ (citation.document_id | string)[:8] }}… · chunk {{ (citation.chunk_id | string)[:8] }}…

{{ citation.excerpt_preview }}{% if citation.excerpt_truncated %} … (truncated){% endif %}
No citations.
{#- Answer -#}
Answer & answerability

{{ badge(trace.answerability.status | replace("_", " "), "ok" if trace.answerability.status == "answerable" else "neutral") }} (a category, not a confidence percentage)

Reason codes: {{ trace.answerability.reasons | join(", ") }}

Evidence count: {{ trace.answerability.evidence_count }} · Document diversity: {{ trace.answerability.document_diversity }} · Source independence: {{ trace.answerability.source_independence }} · Facet coverage: {{ "%.2f" | format(trace.answerability.facet_coverage_ratio) }} · Thresholds version: {{ trace.answerability.thresholds_version }}

Generation is not run by Query Lab: it inspects retrieval and answerability; /v1/answers produces grounded answers from the same context.

{#- Trace -#}
Trace — timings & revisions

Phase timings

{% for name, value in trace.timings_ms.items() %} {% endfor %}
Per-stage timings in milliseconds
{{ name }}{{ "%.1f" | format(value) }} ms

Revisions

  • Embedding profile: {{ trace.revisions.embedding_profile or "unavailable" }}
  • Sparse profile: {{ trace.revisions.sparse_profile }}
  • Collection alias: {{ trace.revisions.collection_alias or "unavailable" }}
  • {% if rerank_active %}
  • Reranker profile: {{ trace.revisions.reranker_profile or "unavailable" }}
  • {% endif %}
  • Answerability thresholds: {{ trace.revisions.answerability_thresholds_version }}

Retrieval run ID: {{ trace.retrieval_run_id }}

{% endif %}
{% endblock %}