fix: route annotation queue score lookups to queriers (#13801)

## Summary

- route Discovery and annotation queue endpoints to queriers so score
lookups, item hydration, and review reads do not fall through to
ingesters
- make Discovery source_stream required at the API response boundary
- cover Discovery, queue item detail, and review routing with regression
tests

The QueueItem remains reference-only. Workbench and enqueue validation
derive source_stream from timestamp-bounded _llm_scores queries in the
enterprise implementation.

Depends on https://github.com/openobserve/o2-enterprise/pull/2423

## Testing

- 5 querier routing tests
- Discovery response serialization test with the enterprise feature
- 16 enterprise annotation queue tests
- 14 enterprise Discovery tests
This commit is contained in:
udev
2026-08-17 05:24:31 +00:00
committed by GitHub
parent d770d0245a
commit 35860aff9d
2 changed files with 16 additions and 5 deletions
+2 -2
View File
@@ -69,7 +69,7 @@ pub struct DiscoveryItemResponseBody {
pub trace_id: Option<String>,
pub session_id: Option<String>,
pub ref_timestamp: i64,
pub source_stream: Option<String>,
pub source_stream: String,
/// Derived quality: `issue` for one unhealthy dimension and `multiple` for
/// two or more unhealthy dimensions.
pub quality: String,
@@ -217,7 +217,7 @@ mod tests {
trace_id: Some("trace-1".to_string()),
session_id: None,
ref_timestamp: 123,
source_stream: Some("traces".to_string()),
source_stream: "traces".to_string(),
quality: DiscoveryQuality::Issue,
issue_count: 1,
context: Some(serde_json::json!({
+14 -3
View File
@@ -14,7 +14,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/// usize indicates the number of parts to skip based on their actual paths.
const QUERIER_ROUTES: [(&str, usize); 32] = [
const QUERIER_ROUTES: [(&str, usize); 34] = [
("config", 0), // /config
("summary", 2), // /api/{org_id}/summary
("organizations", 1), // /api/organizations
@@ -48,8 +48,10 @@ const QUERIER_ROUTES: [(&str, usize); 32] = [
("chat_stream", 3), /* /api/{org_id}/ai/chat_stream
* {label_name}/
* values */
("service_streams", 2), // /api/{org_id}/service_streams/...
("node/list", 2), // /api/_meta/node/list
("discovery", 2), // /api/{org_id}/discovery
("annotation_queues", 2), // /api/{org_id}/annotation_queues/...
("service_streams", 2), // /api/{org_id}/service_streams/...
("node/list", 2), // /api/_meta/node/list
];
const QUERIER_ROUTES_BY_BODY: [&str; 9] = [
"/_search",
@@ -161,6 +163,15 @@ mod tests {
assert!(is_querier_route("/api/org1/service_streams/_correlate"));
assert!(is_querier_route("/api/org1/service_streams/_grouped"));
// AI evaluation reads execute searches and must never fall through to
// the default ingester route.
assert!(is_querier_route("/api/org1/discovery"));
assert!(is_querier_route(
"/api/org1/annotation_queues/queue-1/items/item-1"
));
assert!(is_querier_route(
"/api/org1/annotation_queues/queue-1/items/item-1/reviews"
));
// Test trace detail routes
assert!(is_querier_route(
"/api/org1/default/traces/trace-id/details"