Skip to content

Feat/simplified query#144

Open
Vunovati wants to merge 25 commits into
mainfrom
feat/simplified-query
Open

Feat/simplified query#144
Vunovati wants to merge 25 commits into
mainfrom
feat/simplified-query

Conversation

@Vunovati
Copy link
Copy Markdown
Collaborator

@Vunovati Vunovati commented May 22, 2026

Summary by CodeRabbit

  • New Features

    • Unified KopaiQuery added: SDK query methods and server query endpoints for traces, logs, and metrics (raw & aggregate).
  • UI

    • Dashboard DataSource gains a "query" variant; observability renderers and hooks accept it and now show explicit fallback/errors for incompatible responses. Trace/status labels use Title Case.
  • API

    • Query validation failures surface as HTTP 400 with validation details.
  • Reliability

    • Metric discovery supports on-demand provisioning/backfill.
  • Tests

    • Extensive new unit/integration coverage across query, SDK, datasources, and UI.
  • Documentation

    • Updated dashboard creation examples to a newer tree version.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

Review Change Stack

Warning

Review limit reached

@Vunovati, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 57 minutes and 48 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cb599dbf-e5f4-4e2f-afe2-9b2465bcc2ad

📥 Commits

Reviewing files that changed from the base of the PR and between 5a5a435 and ad5ab71.

📒 Files selected for processing (9)
  • .changeset/simplified-query.md
  • .changeset/ui-core-dedup.md
  • packages/cli/src/client.ts
  • packages/cli/src/config.test.ts
  • packages/cli/src/config.ts
  • packages/sdk/package.json
  • packages/sdk/src/node.test.ts
  • packages/sdk/src/node.ts
  • packages/sdk/tsdown.config.ts
📝 Walkthrough

<review_stack_artifact>

</review_stack_artifact>

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/simplified-query

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
examples/ui-react-app/src/custom-observability-catalog.tsx (1)

461-467: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard only narrows summaries; query responses are still unsafely treated as trace rows.

Now that TraceDetail can receive method: "query", non-summary responses fall into the else path and are cast to OtelTracesRow[] without checking shape. That can break rendering when the query selects different dimensions.

Suggested fix
 function isTraceSummaries(
   props: TraceDetailProps & { hasData: true }
 ): props is Omit<TraceDetailProps & { hasData: true }, "response"> & {
   response: SearchResult<TraceSummaryRow> | null;
 } {
   return props.element.dataSource?.method === "searchTraceSummariesPage";
 }
+
+function isTraceRows(
+  props: TraceDetailProps & { hasData: true }
+): props is Omit<TraceDetailProps & { hasData: true }, "response"> & {
+  response: SearchResult<OtelTracesRow> | null;
+} {
+  return props.element.dataSource?.method === "searchTracesPage";
+}

Then branch in TraceDetail with isTraceRows(props) and add a safe fallback for unsupported query shapes (instead of casting).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/ui-react-app/src/custom-observability-catalog.tsx` around lines 461
- 467, The current type guard isTraceSummaries only narrows summary responses,
leaving the "query" branch in TraceDetail to unsafely cast to OtelTracesRow[];
add a new type guard isTraceRows that checks props.element.dataSource?.method
=== "query" and validates the response shape (e.g., existence of expected row
fields) so TraceDetail can safely branch: use isTraceSummaries(...) for
summaries, isTraceRows(...) for true trace rows, and in the else (unsupported
query shapes) return a safe fallback UI/path instead of casting to
OtelTracesRow[]; update TraceDetail to use these guards and remove the unsafe
cast.
🧹 Nitpick comments (2)
packages/core/src/telemetry-datasource.ts (1)

165-187: ⚡ Quick win

Tighten per-method return types to preserve aggregate output shape.

The specialized methods currently erase output.type result distinctions (notably bucket_start for timeSeries). Reusing KopaiQueryResult<...> keeps these methods aligned with the generic query() contract.

Suggested typing update
   queryTracesRaw(
     q: TraceRawQuery & { requestContext?: unknown }
-  ): Promise<{ data: OtelTracesRow[]; nextCursor: string | null }>;
+  ): Promise<KopaiQueryResult<TraceRawQuery>>;

   queryTracesAggregate(
     q: TraceAggregateQuery & { requestContext?: unknown }
-  ): Promise<{ data: KopaiAggregateRow[] }>;
+  ): Promise<KopaiQueryResult<TraceAggregateQuery>>;

   queryLogsRaw(
     q: LogRawQuery & { requestContext?: unknown }
-  ): Promise<{ data: OtelLogsRow[]; nextCursor: string | null }>;
+  ): Promise<KopaiQueryResult<LogRawQuery>>;

   queryLogsAggregate(
     q: LogAggregateQuery & { requestContext?: unknown }
-  ): Promise<{ data: KopaiAggregateRow[] }>;
+  ): Promise<KopaiQueryResult<LogAggregateQuery>>;

   queryMetricsRaw(
     q: MetricRawQuery & { requestContext?: unknown }
-  ): Promise<{ data: OtelMetricsRow[]; nextCursor: string | null }>;
+  ): Promise<KopaiQueryResult<MetricRawQuery>>;

   queryMetricsAggregate(
     q: MetricAggregateQuery & { requestContext?: unknown }
-  ): Promise<{ data: KopaiAggregateRow[] }>;
+  ): Promise<KopaiQueryResult<MetricAggregateQuery>>;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/telemetry-datasource.ts` around lines 165 - 187, The
aggregate (and raw) method signatures currently return plain shapes that drop
the KopaiQueryResult output typing (losing distinctions like
output.type/bucket_start); update the signatures for queryTracesAggregate,
queryLogsAggregate, queryMetricsAggregate (and likewise the raw variants
queryTracesRaw, queryLogsRaw, queryMetricsRaw if you want consistent behavior)
to return Promise<KopaiQueryResult<...>> (e.g.,
Promise<KopaiQueryResult<KopaiAggregateRow>> for aggregates and
Promise<KopaiQueryResult<OtelTracesRow>>/OtelLogsRow/OtelMetricsRow for raw)
instead of Promise<{ data: ...; nextCursor?: ... }>, so the methods preserve the
full KopaiQueryResult shape and its output.type information.
packages/sdk/src/kopai-query-builder.ts (1)

123-177: resolveColumn intentionally keeps semconv strings like "service.name" as strings (no mismatch with the test).

STRUCTURAL_SET in packages/sdk/src/kopai-query-builder.ts is built from kopaiQuery.TraceColumn.options, and TraceColumn includes both structural fields and semconv dotted keys (e.g. "service.name"). So resolveColumn("service.name", "traces") returns "service.name" unchanged, matching it("semconv string stays string").

  • Minor: rename STRUCTURAL_SET to something like TOP_LEVEL_COLUMN_SET for clarity (it’s not only structural).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/sdk/src/kopai-query-builder.ts` around lines 123 - 177, The constant
name STRUCTURAL_SET is misleading because it contains top-level/semconv column
names; rename it to TOP_LEVEL_COLUMN_SET (update its declaration and all
references, e.g., in resolveColumn and any other usages like inferContainer
logic) so the identifier better reflects its contents while leaving the
value/behavior unchanged; ensure you update the const name in the same module
and run tests to confirm resolveColumn("service.name", "traces") still returns
the string.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/clickhouse-datasource/src/query-kopai.ts`:
- Around line 590-603: The cursor handling currently only validates timestamp in
parseCursor but binds c.id as UInt64 (used in nextParam calls) which can allow
non-numeric hashes to reach execution; update parseCursor (or add a validation
step right after it in the query-building code that uses parseCursor) to ensure
c.id is a valid unsigned 64-bit integer (numeric string or BigInt) before
calling nextParam with type UInt64, and if validation fails throw/return a clear
query-validation error; reference parseCursor, c.id, nextParam, and the code
paths that push the conds using sipHash64 so the invalid cursor is rejected
early rather than causing runtime execution errors.
- Around line 522-544: The cursor predicate logic always uses Timestamp (and
SpanId) regardless of the actual ORDER BY, which causes incorrect pagination
when the primary sort is not time; update the pagination to either (A) validate
and reject unsupported combos by checking the primary sort field returned by
compileOrderByRaw/inferPrimaryDir and throwing a clear error when it's not the
time column (Timestamp/TimeUnix), or (B) build the cursor predicate from the
actual primary sort expression and a stable secondary tiebreaker (use the
compiled primary column name from compileOrderByRaw and keep SpanId as the
tiebreaker) so parseCursor/nextParam/nanosToDateTime64 are used only when the
primary is a time field; modify the block that uses parseCursor, nextParam,
inferPrimaryDir, compileOrderByRaw, and ensureTiebreaker accordingly to
implement one of these fixes.

In `@packages/core/src/kopai-query.ts`:
- Around line 17-22: DurationString currently allows zero values (regex uses
\d+), which conflicts with the compiler that rejects zero durations; update the
DurationString schema (the constant DurationString) to only accept positive
integers greater than zero by changing the numeric part of the regex to a
non-zero-leading pattern (e.g. use [1-9]\d*) and adjust the error message to
state "positive integer > 0" while keeping the same unit set (s,m,h,d,w) so
schema and compiler validation match.

In `@packages/sqlite-datasource/src/query-builder.ts`:
- Around line 442-462: The code currently accepts arbitrary order clauses in raw
mode which breaks the cursor format; change the branch that handles order (the
block that iterates order and uses assertColumnRef and columnSqlExpr to build
orderParts/orderParams) to instead reject any explicit order when in raw mode by
throwing kopaiQueryCompiler.KopaiQueryValidationError (same style as the
existing measure check), so only the default ordering produced by
kopaiQueryCompiler.timeColumnForSignal(signal) plus the tiebreak (tiebreak =
signal === "traces" ? "SpanId" : "rowid") is used; in short, if order is
non-empty in raw mode, throw a validation error and do not build orderParts from
user-supplied columns.
- Around line 825-831: The normalizeCellValue function currently coerces all
bigints to Number (Number(v)), which can silently lose precision for large
aggregate results; change the bigint branch in normalizeCellValue to return a
string representation (e.g., String(v) or v.toString()) instead of Number(v) so
large integer aggregates are preserved (KopaiAggregateRow already permits
strings) and other branches remain unchanged.
- Around line 335-358: Validate the cursor parts tsStr and idStr before
attempting BigInt or parseInt: check tsStr matches /^\d+$/ and idStr matches
/^\d+$/ for non-"traces" signals, and if either fails throw
kopaiQueryCompiler.KopaiQueryValidationError with a clear message; only then
call BigInt(tsStr) and parseInt(idStr, 10) (keeping the existing
timeColumnForSignal(signal), traces/direction, SpanId logic and the existing
rowid/Number.isNaN guard) so malformed timestamps or ids produce the intended
validation error instead of raw parsing exceptions or partial parse behavior.

---

Outside diff comments:
In `@examples/ui-react-app/src/custom-observability-catalog.tsx`:
- Around line 461-467: The current type guard isTraceSummaries only narrows
summary responses, leaving the "query" branch in TraceDetail to unsafely cast to
OtelTracesRow[]; add a new type guard isTraceRows that checks
props.element.dataSource?.method === "query" and validates the response shape
(e.g., existence of expected row fields) so TraceDetail can safely branch: use
isTraceSummaries(...) for summaries, isTraceRows(...) for true trace rows, and
in the else (unsupported query shapes) return a safe fallback UI/path instead of
casting to OtelTracesRow[]; update TraceDetail to use these guards and remove
the unsafe cast.

---

Nitpick comments:
In `@packages/core/src/telemetry-datasource.ts`:
- Around line 165-187: The aggregate (and raw) method signatures currently
return plain shapes that drop the KopaiQueryResult output typing (losing
distinctions like output.type/bucket_start); update the signatures for
queryTracesAggregate, queryLogsAggregate, queryMetricsAggregate (and likewise
the raw variants queryTracesRaw, queryLogsRaw, queryMetricsRaw if you want
consistent behavior) to return Promise<KopaiQueryResult<...>> (e.g.,
Promise<KopaiQueryResult<KopaiAggregateRow>> for aggregates and
Promise<KopaiQueryResult<OtelTracesRow>>/OtelLogsRow/OtelMetricsRow for raw)
instead of Promise<{ data: ...; nextCursor?: ... }>, so the methods preserve the
full KopaiQueryResult shape and its output.type information.

In `@packages/sdk/src/kopai-query-builder.ts`:
- Around line 123-177: The constant name STRUCTURAL_SET is misleading because it
contains top-level/semconv column names; rename it to TOP_LEVEL_COLUMN_SET
(update its declaration and all references, e.g., in resolveColumn and any other
usages like inferContainer logic) so the identifier better reflects its contents
while leaving the value/behavior unchanged; ensure you update the const name in
the same module and run tests to confirm resolveColumn("service.name", "traces")
still returns the string.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 25b0619d-4021-4e4e-ac82-4dfdc04ff890

📥 Commits

Reviewing files that changed from the base of the PR and between 3a9729e and 56bb2ad.

⛔ Files ignored due to path filters (1)
  • packages/ui-core/src/lib/__snapshots__/generate-prompt-instructions.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (41)
  • examples/ui-react-app/src/custom-observability-catalog.tsx
  • packages/api/src/index.test.ts
  • packages/api/src/index.ts
  • packages/api/src/routes/error-handler.ts
  • packages/api/src/routes/query.ts
  • packages/api/src/signals-query.test.ts
  • packages/api/src/signals.test.ts
  • packages/clickhouse-datasource/src/datasource-query-six.test.ts
  • packages/clickhouse-datasource/src/datasource-query.test.ts
  • packages/clickhouse-datasource/src/datasource.ts
  • packages/clickhouse-datasource/src/query-kopai.test.ts
  • packages/clickhouse-datasource/src/query-kopai.ts
  • packages/core/src/denormalized-signals-zod.ts
  • packages/core/src/index.ts
  • packages/core/src/kopai-query-compiler.test.ts
  • packages/core/src/kopai-query-compiler.ts
  • packages/core/src/kopai-query.test.ts
  • packages/core/src/kopai-query.ts
  • packages/core/src/telemetry-datasource.ts
  • packages/sdk/src/client.test.ts
  • packages/sdk/src/client.ts
  • packages/sdk/src/index.ts
  • packages/sdk/src/kopai-query-builder.test.ts
  • packages/sdk/src/kopai-query-builder.ts
  • packages/sqlite-datasource/src/datasource-query-six.test.ts
  • packages/sqlite-datasource/src/datasource-query.test.ts
  • packages/sqlite-datasource/src/db-datasource.ts
  • packages/sqlite-datasource/src/optimized-datasource.ts
  • packages/sqlite-datasource/src/query-builder.test.ts
  • packages/sqlite-datasource/src/query-builder.ts
  • packages/ui-core/src/hooks/use-kopai-data.test.ts
  • packages/ui-core/src/hooks/use-kopai-data.ts
  • packages/ui-core/src/hooks/use-live-logs.test.ts
  • packages/ui-core/src/lib/component-catalog.test.ts
  • packages/ui-core/src/lib/component-catalog.ts
  • packages/ui-core/src/lib/observability-catalog.ts
  • packages/ui-core/src/providers/kopai-provider.tsx
  • packages/ui/src/components/observability/DynamicDashboard/DynamicDashboard.test.tsx
  • packages/ui/src/pages/observability.test.tsx
  • skills/create-dashboard/SKILL.md
  • skills/create-dashboard/rules/workflow.md

Comment thread packages/clickhouse-datasource/src/query-kopai.ts
Comment thread packages/clickhouse-datasource/src/query-kopai.ts
Comment thread packages/core/src/kopai-query.ts
Comment thread packages/sqlite-datasource/src/query-builder.ts
Comment thread packages/sqlite-datasource/src/query-builder.ts
Comment thread packages/sqlite-datasource/src/query-builder.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/ui-react-app/src/custom-observability-catalog.tsx`:
- Around line 487-489: The current type-guard only checks the first element
(data[0]) which can miss malformed later items; update the guard to verify every
element using hasTraceRowShape so the branch is truly narrowed for all rows:
keep the Array.isArray check, return true for an empty array, and replace the
single-element check with data.every(hasTraceRowShape) to validate all items
before treating data as TraceRow[].
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 545e1f4e-a21c-40ce-8944-b920a0be7fc8

📥 Commits

Reviewing files that changed from the base of the PR and between 56bb2ad and c270ec5.

⛔ Files ignored due to path filters (1)
  • packages/ui-core/src/lib/__snapshots__/generate-prompt-instructions.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (8)
  • examples/ui-react-app/src/custom-observability-catalog.tsx
  • packages/clickhouse-datasource/src/query-kopai.test.ts
  • packages/clickhouse-datasource/src/query-kopai.ts
  • packages/core/src/kopai-query.test.ts
  • packages/core/src/kopai-query.ts
  • packages/sdk/src/kopai-query-builder.ts
  • packages/sqlite-datasource/src/query-builder.test.ts
  • packages/sqlite-datasource/src/query-builder.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/core/src/kopai-query.test.ts
  • packages/sqlite-datasource/src/query-builder.ts
  • packages/sdk/src/kopai-query-builder.ts
  • packages/core/src/kopai-query.ts
  • packages/clickhouse-datasource/src/query-kopai.ts

Comment thread examples/ui-react-app/src/custom-observability-catalog.tsx Outdated
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

Actionable comments posted: 0

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ui/src/components/observability/renderers/narrowRows.test.ts`:
- Around line 26-31: The test name is misleading — it currently says "returns
null..." but the assertion expects one metric row; update the test title to
reflect that a row missing the synthetic MetricType is still considered a metric
row. Locate the test in
packages/ui/src/components/observability/renderers/narrowRows.test.ts and change
the description for the it(...) case that calls narrowRows(res,
hasMetricRowShape) so it states something like "returns row when a metric
renderer receives raw metric rows lacking the synthetic MetricType" (or
equivalent clear wording) to match the expect(...).toHaveLength(1) assertion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2057c8f8-ecd8-4fbc-8533-0dbc57204f30

📥 Commits

Reviewing files that changed from the base of the PR and between f0f174a and 00fda25.

⛔ Files ignored due to path filters (1)
  • packages/ui-core/src/lib/__snapshots__/generate-prompt-instructions.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (28)
  • examples/ui-react-app/src/custom-observability-catalog.tsx
  • packages/clickhouse-datasource/src/datasource-coerce.test.ts
  • packages/clickhouse-datasource/src/datasource-query.test.ts
  • packages/clickhouse-datasource/src/datasource.ts
  • packages/clickhouse-datasource/src/query-kopai.test.ts
  • packages/clickhouse-datasource/src/query-kopai.ts
  • packages/core/src/kopai-query-compiler.test.ts
  • packages/core/src/kopai-query-compiler.ts
  • packages/core/src/kopai-query.test.ts
  • packages/core/src/kopai-query.ts
  • packages/sdk/src/client.test.ts
  • packages/sdk/src/client.ts
  • packages/sdk/src/index.ts
  • packages/sdk/src/kopai-query-builder.test.ts
  • packages/sdk/src/kopai-query-builder.ts
  • packages/sqlite-datasource/src/datasource-query.test.ts
  • packages/sqlite-datasource/src/query-builder.test.ts
  • packages/sqlite-datasource/src/query-builder.ts
  • packages/ui-core/src/lib/renderer.test.tsx
  • packages/ui-core/src/lib/renderer.tsx
  • packages/ui/src/components/observability/renderers/OtelLogTimeline.tsx
  • packages/ui/src/components/observability/renderers/OtelMetricHistogram.tsx
  • packages/ui/src/components/observability/renderers/OtelMetricStat.tsx
  • packages/ui/src/components/observability/renderers/OtelMetricTable.tsx
  • packages/ui/src/components/observability/renderers/OtelMetricTimeSeries.tsx
  • packages/ui/src/components/observability/renderers/OtelTraceDetail.tsx
  • packages/ui/src/components/observability/renderers/narrowRows.test.ts
  • packages/ui/src/components/observability/renderers/narrowRows.ts
🚧 Files skipped from review as they are similar to previous changes (12)
  • packages/sdk/src/index.ts
  • packages/core/src/kopai-query.test.ts
  • packages/sqlite-datasource/src/datasource-query.test.ts
  • packages/sqlite-datasource/src/query-builder.test.ts
  • packages/core/src/kopai-query-compiler.ts
  • packages/sdk/src/client.test.ts
  • packages/clickhouse-datasource/src/datasource-query.test.ts
  • packages/clickhouse-datasource/src/datasource.ts
  • packages/sdk/src/kopai-query-builder.ts
  • packages/clickhouse-datasource/src/query-kopai.ts
  • packages/clickhouse-datasource/src/query-kopai.test.ts
  • packages/sdk/src/kopai-query-builder.test.ts

Comment thread packages/ui/src/components/observability/renderers/narrowRows.test.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
packages/ui/src/components/observability/renderers/narrowRows.ts (1)

105-115: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Require Timestamp in hasTraceRowShape.

Right now any aggregate row that happens to include TraceId, SpanId, and one span-only key like SpanName will pass this guard, so narrowQueryRows can forward a wrong-shaped result instead of surfacing the mismatch error this helper was added for. Requiring the raw trace timestamp closes that hole and matches the actual trace row contract.

Proposed fix
 export function hasTraceRowShape(v: unknown): v is OtelTracesRow {
   if (!isRecord(v)) return false;
   // Traces require SpanId + TraceId, but so can a trace-correlated log; the
   // presence of a span-only structural key distinguishes a real span row.
   return (
+    typeof v.Timestamp === "string" &&
     typeof v.SpanId === "string" &&
     typeof v.TraceId === "string" &&
     typeof v.TimeUnix !== "string" &&
     hasAnyKey(v, SPAN_ONLY_KEYS) &&
     !hasAnyKey(v, LOG_ONLY_KEYS)
   );
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/components/observability/renderers/narrowRows.ts` around
lines 105 - 115, hasTraceRowShape currently lets aggregate rows through because
it doesn't require the raw trace timestamp; update the predicate in
hasTraceRowShape to explicitly require the trace timestamp by adding a check
like typeof v.Timestamp === "string" (instead of the existing typeof v.TimeUnix
!== "string"), so the function (used with OtelTracesRow and keys SPAN_ONLY_KEYS
/ LOG_ONLY_KEYS) only returns true when TraceId, SpanId and a properly typed
Timestamp are present along with a span-only key and no log-only keys.
packages/sqlite-datasource/src/db-datasource.ts (2)

1425-1436: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Await the runner inside guardKopaiQuery.

This wrapper only catches synchronous throws right now. The callbacks here return promises, so any rejection from runRawTraces, runRawLogs, runRawMetrics, or runAggregate will bypass this envelope and escape without the advertised SqliteDatasourceQueryError wrapping.

Proposed fix
-  private guardKopaiQuery<T>(run: () => T): T {
+  private async guardKopaiQuery<T>(
+    run: () => Promise<T> | T
+  ): Promise<T> {
     try {
-      return run();
+      return await run();
     } catch (error) {
       if (error instanceof SqliteDatasourceQueryError) throw error;
       if (error instanceof kopaiQueryCompiler.KopaiQueryValidationError) {
         throw error;
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/sqlite-datasource/src/db-datasource.ts` around lines 1425 - 1436,
guardKopaiQuery currently only catches synchronous throws; make it handle
promise rejections by awaiting the runner: change guardKopaiQuery to an async
function that returns Promise<T>, await the call to run(), and keep the same
error handling logic (re-throw SqliteDatasourceQueryError and
kopaiQueryCompiler.KopaiQueryValidationError, otherwise throw new
SqliteDatasourceQueryError with the original error as cause). Update all callers
(e.g., runRawTraces, runRawLogs, runRawMetrics, runAggregate) to await the
returned promise if necessary.

1274-1295: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Use the compiler-owned error-status literal here as well.

These summary queries still hardcode "Error" even though the rest of this PR moves status-name mapping behind kopaiQueryCompiler. Leaving SQLite on a raw string makes errorCount/hasError the next place backend behavior drifts if that canonical literal changes again.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/sqlite-datasource/src/db-datasource.ts` around lines 1274 - 1295,
The queries aggSql and svcSql currently hardcode the status string "Error";
replace that literal with the compiler-owned error-status literal from
kopaiQueryCompiler (e.g., kopaiQueryCompiler.errorStatusLiteral or the actual
property name used on the compiler instance) so SQLite uses the canonical status
name; update the template strings for aggSql and svcSql to interpolate that
compiler-provided literal (or pass it as a bound parameter) instead of "Error",
and keep the rest of the logic that uses aggSql, svcSql and
this.sqliteConnection.prepare(...).all(..., ...traceIds) intact.
🧹 Nitpick comments (2)
packages/ui/src/components/observability/TraceTimeline/index.tsx (1)

102-103: ⚡ Quick win

Consider adding case normalization at the data boundary.

These defaults now use title-case ("Internal", "Unset"), but if row.SpanKind or row.StatusCode arrive from the backend in uppercase (e.g., "INTERNAL", "UNSET", "ERROR"), the UI comparisons throughout the codebase will fail. This is the critical transform point between backend data and UI models.

🔄 Add normalization helper if backend uses different casing

If verification reveals the backend sends uppercase values, add normalization here:

+function normalizeStatus(status: string | undefined): SpanNode["status"] | undefined {
+  if (!status) return undefined;
+  // Map OpenTelemetry uppercase to title-case
+  const statusMap: Record<string, SpanNode["status"]> = {
+    "UNSET": "Unset",
+    "OK": "Ok", 
+    "ERROR": "Error",
+  };
+  return statusMap[status.toUpperCase()] ?? status as SpanNode["status"];
+}
+
+function normalizeKind(kind: string | undefined): string | undefined {
+  if (!kind) return undefined;
+  // Capitalize first letter, lowercase rest
+  return kind.charAt(0).toUpperCase() + kind.slice(1).toLowerCase();
+}

 const span: SpanNode = {
   spanId: row.SpanId,
   parentSpanId: row.ParentSpanId || undefined,
   traceId: row.TraceId,
   name: row.SpanName ?? "",
   startTimeUnixMs: startMs,
   endTimeUnixMs: endMs,
   durationMs,
-  kind: row.SpanKind ?? "Internal",
-  status: row.StatusCode ?? "Unset",
+  kind: normalizeKind(row.SpanKind) ?? "Internal",
+  status: normalizeStatus(row.StatusCode) ?? "Unset",
   statusMessage: row.StatusMessage,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/components/observability/TraceTimeline/index.tsx` around
lines 102 - 103, The mapping that sets kind: row.SpanKind ?? "Internal" and
status: row.StatusCode ?? "Unset" must normalize incoming casing so UI
comparisons work regardless of backend case; update the transform in
TraceTimeline (index.tsx) to canonicalize row.SpanKind and row.StatusCode (e.g.,
trim + toLowerCase/upperCase then map to the UI enum or title-case) and/or add
small helpers (normalizeSpanKind, normalizeStatus) used in this mapping to
return the expected "Internal"/"Unset"/"Error" tokens while still falling back
to the defaults.
packages/clickhouse-datasource/src/datasource.test.ts (1)

1614-1699: ⚡ Quick win

Assert the provisioning side effect explicitly.

This suite still passes if discoverMetrics() falls back to full-table scans, because it only checks returned metrics. Since this describe is meant to pin the new on-demand provisioning path, add a postcondition after the first call that DISCOVER_NAMES_TABLE, DISCOVER_ATTRS_TABLE, and at least one discover MV now exist. Otherwise a regression in the create/backfill path can slip through unnoticed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/clickhouse-datasource/src/datasource.test.ts` around lines 1614 -
1699, The test only asserts returned metrics but not that on-demand provisioning
actually created the discovery tables/MVs; after calling ds.discoverMetrics() in
the provisioning tests (the ones using dropDiscoverMVs and the "provisions…"
cases), add assertions that DISCOVER_NAMES_TABLE and DISCOVER_ATTRS_TABLE now
exist and that at least one of the materialized views from
getDiscoverMVSchema(TEST_DATABASE).materializedViews was created (use
adminClient to check existence via system.tables or a DROP/EXISTS-style query);
place these checks immediately after the first discoverMetrics() call in the
relevant it blocks to verify the create/backfill side-effect for discoverMetrics
and prevent regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/clickhouse-datasource/src/datasource.ts`:
- Around line 1082-1099: The current discoverMetrics request path calls
provisionDiscoverMVs and backfills (provisionDiscoverMVs, readDiscoverMVs) when
CH_ERR_TABLE_NOT_FOUND, which can block/timeout and cause stampedes; change this
to not perform DDL/backfill inline: instead detect the missing MVs, log and
return a controlled error/placeholder response to the client (or a fast empty
result) and enqueue a single background/one-time job (use a cross-request
mutex/leader-election or an in-memory/Redis/DB lock keyed by database + function
like provisionDiscoverMVs) to perform provisioning/backfill off-request,
ensuring concurrent discoverMetrics calls observe the lock/flag and do not
re-queue the job; alternatively move provisioning to startup/admin flow and call
provisionDiscoverMVs only from that background/administrative path.

---

Outside diff comments:
In `@packages/sqlite-datasource/src/db-datasource.ts`:
- Around line 1425-1436: guardKopaiQuery currently only catches synchronous
throws; make it handle promise rejections by awaiting the runner: change
guardKopaiQuery to an async function that returns Promise<T>, await the call to
run(), and keep the same error handling logic (re-throw
SqliteDatasourceQueryError and kopaiQueryCompiler.KopaiQueryValidationError,
otherwise throw new SqliteDatasourceQueryError with the original error as
cause). Update all callers (e.g., runRawTraces, runRawLogs, runRawMetrics,
runAggregate) to await the returned promise if necessary.
- Around line 1274-1295: The queries aggSql and svcSql currently hardcode the
status string "Error"; replace that literal with the compiler-owned error-status
literal from kopaiQueryCompiler (e.g., kopaiQueryCompiler.errorStatusLiteral or
the actual property name used on the compiler instance) so SQLite uses the
canonical status name; update the template strings for aggSql and svcSql to
interpolate that compiler-provided literal (or pass it as a bound parameter)
instead of "Error", and keep the rest of the logic that uses aggSql, svcSql and
this.sqliteConnection.prepare(...).all(..., ...traceIds) intact.

In `@packages/ui/src/components/observability/renderers/narrowRows.ts`:
- Around line 105-115: hasTraceRowShape currently lets aggregate rows through
because it doesn't require the raw trace timestamp; update the predicate in
hasTraceRowShape to explicitly require the trace timestamp by adding a check
like typeof v.Timestamp === "string" (instead of the existing typeof v.TimeUnix
!== "string"), so the function (used with OtelTracesRow and keys SPAN_ONLY_KEYS
/ LOG_ONLY_KEYS) only returns true when TraceId, SpanId and a properly typed
Timestamp are present along with a span-only key and no log-only keys.

---

Nitpick comments:
In `@packages/clickhouse-datasource/src/datasource.test.ts`:
- Around line 1614-1699: The test only asserts returned metrics but not that
on-demand provisioning actually created the discovery tables/MVs; after calling
ds.discoverMetrics() in the provisioning tests (the ones using dropDiscoverMVs
and the "provisions…" cases), add assertions that DISCOVER_NAMES_TABLE and
DISCOVER_ATTRS_TABLE now exist and that at least one of the materialized views
from getDiscoverMVSchema(TEST_DATABASE).materializedViews was created (use
adminClient to check existence via system.tables or a DROP/EXISTS-style query);
place these checks immediately after the first discoverMetrics() call in the
relevant it blocks to verify the create/backfill side-effect for discoverMetrics
and prevent regressions.

In `@packages/ui/src/components/observability/TraceTimeline/index.tsx`:
- Around line 102-103: The mapping that sets kind: row.SpanKind ?? "Internal"
and status: row.StatusCode ?? "Unset" must normalize incoming casing so UI
comparisons work regardless of backend case; update the transform in
TraceTimeline (index.tsx) to canonicalize row.SpanKind and row.StatusCode (e.g.,
trim + toLowerCase/upperCase then map to the UI enum or title-case) and/or add
small helpers (normalizeSpanKind, normalizeStatus) used in this mapping to
return the expected "Internal"/"Unset"/"Error" tokens while still falling back
to the defaults.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 715e4a2c-ada2-4050-8ac0-aa8b833a34b5

📥 Commits

Reviewing files that changed from the base of the PR and between 00fda25 and 2f8c869.

⛔ Files ignored due to path filters (1)
  • packages/ui-core/src/lib/__snapshots__/generate-prompt-instructions.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (43)
  • .changeset/sdk-error-detail-message.md
  • .changeset/simplified-query.md
  • .changeset/ui-core-dedup.md
  • packages/clickhouse-datasource/src/datasource-coerce.test.ts
  • packages/clickhouse-datasource/src/datasource-query-six.test.ts
  • packages/clickhouse-datasource/src/datasource-query.test.ts
  • packages/clickhouse-datasource/src/datasource.test.ts
  • packages/clickhouse-datasource/src/datasource.ts
  • packages/clickhouse-datasource/src/discover-mv-schema.ts
  • packages/clickhouse-datasource/src/e2e.integration.test.ts
  • packages/clickhouse-datasource/src/query-traces.ts
  • packages/clickhouse-datasource/src/test/otel-ddl.ts
  • packages/core/src/denormalized-signals-zod.ts
  • packages/core/src/kopai-query-compiler.ts
  • packages/core/src/kopai-query.ts
  • packages/sdk/src/client.test.ts
  • packages/sdk/src/kopai-query-builder.test.ts
  • packages/sdk/src/request.ts
  • packages/sqlite-datasource/src/datasource-query.test.ts
  • packages/sqlite-datasource/src/datasource-read.test.ts
  • packages/sqlite-datasource/src/datasource-write.test.ts
  • packages/sqlite-datasource/src/db-datasource.ts
  • packages/sqlite-datasource/src/query-builder.test.ts
  • packages/sqlite-datasource/src/query-builder.ts
  • packages/ui-core/src/lib/component-catalog.test.ts
  • packages/ui/src/components/observability/DynamicDashboard/DynamicDashboard.test.tsx
  • packages/ui/src/components/observability/TraceTimeline/GraphView.tsx
  • packages/ui/src/components/observability/TraceTimeline/Minimap.tsx
  • packages/ui/src/components/observability/TraceTimeline/SpanDetailInline.tsx
  • packages/ui/src/components/observability/TraceTimeline/SpanRow.tsx
  • packages/ui/src/components/observability/TraceTimeline/TimelineBar.tsx
  • packages/ui/src/components/observability/TraceTimeline/index.tsx
  • packages/ui/src/components/observability/__fixtures__/trace-summaries.ts
  • packages/ui/src/components/observability/__fixtures__/traces.ts
  • packages/ui/src/components/observability/renderers/OtelMetricHistogram.tsx
  • packages/ui/src/components/observability/renderers/OtelMetricStat.tsx
  • packages/ui/src/components/observability/renderers/OtelMetricTable.tsx
  • packages/ui/src/components/observability/renderers/OtelMetricTimeSeries.tsx
  • packages/ui/src/components/observability/renderers/OtelTraceDetail.tsx
  • packages/ui/src/components/observability/renderers/narrowRows.test.ts
  • packages/ui/src/components/observability/renderers/narrowRows.ts
  • packages/ui/src/components/observability/types.ts
  • packages/ui/src/pages/observability.tsx
💤 Files with no reviewable changes (1)
  • packages/ui-core/src/lib/component-catalog.test.ts
✅ Files skipped from review due to trivial changes (5)
  • packages/ui/src/components/observability/types.ts
  • .changeset/sdk-error-detail-message.md
  • .changeset/ui-core-dedup.md
  • .changeset/simplified-query.md
  • packages/ui/src/components/observability/fixtures/trace-summaries.ts
🚧 Files skipped from review as they are similar to previous changes (15)
  • packages/ui/src/components/observability/renderers/OtelMetricTable.tsx
  • packages/ui/src/components/observability/renderers/OtelTraceDetail.tsx
  • packages/ui/src/components/observability/renderers/OtelMetricStat.tsx
  • packages/ui/src/components/observability/DynamicDashboard/DynamicDashboard.test.tsx
  • packages/ui/src/components/observability/renderers/OtelMetricHistogram.tsx
  • packages/ui/src/components/observability/renderers/OtelMetricTimeSeries.tsx
  • packages/core/src/denormalized-signals-zod.ts
  • packages/sdk/src/client.test.ts
  • packages/core/src/kopai-query-compiler.ts
  • packages/clickhouse-datasource/src/datasource-query-six.test.ts
  • packages/clickhouse-datasource/src/datasource-query.test.ts
  • packages/sqlite-datasource/src/query-builder.test.ts
  • packages/sqlite-datasource/src/query-builder.ts
  • packages/sqlite-datasource/src/datasource-query.test.ts
  • packages/core/src/kopai-query.ts

Comment thread packages/clickhouse-datasource/src/datasource.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/clickhouse-datasource/src/datasource.ts (1)

59-94: ⚡ Quick win

Consider dedicated unit tests for the complex numeric coercion logic.

coerceMeasureCellValue handles several edge cases: bigint overflow detection, integer vs. float string parsing, and NaN fallback. While the logic appears correct and is exercised through integration tests, dedicated unit tests would provide additional confidence for this exported function, especially for the precision-preserving bigint paths.

Example test cases to consider
// Bigint edge cases
coerceMeasureCellValue(String(Number.MAX_SAFE_INTEGER + 1)) // should return string
coerceMeasureCellValue(String(Number.MAX_SAFE_INTEGER)) // should return number
coerceMeasureCellValue("9007199254740992") // boundary check

// Float strings
coerceMeasureCellValue("123.456") // should return 123.456

// Non-numeric
coerceMeasureCellValue("abc") // should return "abc"

// ClickHouse UInt64 strings (common case)
coerceMeasureCellValue("42") // should return 42
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/clickhouse-datasource/src/datasource.ts` around lines 59 - 94, Add
dedicated unit tests for the exported function coerceMeasureCellValue to cover
bigint overflow detection, integer vs float string parsing, NaN fallback, and
boolean/null handling; specifically write tests that assert
String(Number.MAX_SAFE_INTEGER + 1) and "9007199254740992" remain strings,
String(Number.MAX_SAFE_INTEGER) and "42" convert to numbers, "123.456" converts
to a numeric float, non-numeric "abc" returns the original string, boolean
true/false map to 1/0, null/undefined return null, and BigInt inputs above/below
Number.MAX_SAFE_INTEGER/Number.MIN_SAFE_INTEGER follow the same string/number
behavior so the function (coerceMeasureCellValue) behavior is fully covered and
guarded against regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/clickhouse-datasource/src/datasource.test.ts`:
- Around line 2003-2014: The test suite has a contradictory contract for
discoverMetrics: one test (this block using tenantBRequestContext and
discoverMetrics) expects runtime MV provisioning, while other tests assert
discoverMetrics must be read-only and fall back to base-table scans when MVs are
absent; pick one behavior and make the suite consistent. To fix, either update
this test to assert the read-only fallback (remove expectations that MVs are
provisioned and that tenant B gets newly backfilled tables) or change the
implementation of discoverMetrics to perform tenant-scoped MV provisioning and
update the other tests that assert read-only behavior; locate usages of
discoverMetrics and tenantBRequestContext in the suite and align all assertions
to the chosen contract. Ensure any test that assumes provisioning explicitly
mocks or sets the provisioning flag so behavior is deterministic.

---

Nitpick comments:
In `@packages/clickhouse-datasource/src/datasource.ts`:
- Around line 59-94: Add dedicated unit tests for the exported function
coerceMeasureCellValue to cover bigint overflow detection, integer vs float
string parsing, NaN fallback, and boolean/null handling; specifically write
tests that assert String(Number.MAX_SAFE_INTEGER + 1) and "9007199254740992"
remain strings, String(Number.MAX_SAFE_INTEGER) and "42" convert to numbers,
"123.456" converts to a numeric float, non-numeric "abc" returns the original
string, boolean true/false map to 1/0, null/undefined return null, and BigInt
inputs above/below Number.MAX_SAFE_INTEGER/Number.MIN_SAFE_INTEGER follow the
same string/number behavior so the function (coerceMeasureCellValue) behavior is
fully covered and guarded against regressions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 59d29c98-2272-428f-940e-13ac873e6ff6

📥 Commits

Reviewing files that changed from the base of the PR and between 00fda25 and 5a5a435.

⛔ Files ignored due to path filters (1)
  • packages/ui-core/src/lib/__snapshots__/generate-prompt-instructions.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (43)
  • .changeset/sdk-error-detail-message.md
  • .changeset/simplified-query.md
  • .changeset/ui-core-dedup.md
  • packages/clickhouse-datasource/src/datasource-coerce.test.ts
  • packages/clickhouse-datasource/src/datasource-query-six.test.ts
  • packages/clickhouse-datasource/src/datasource-query.test.ts
  • packages/clickhouse-datasource/src/datasource.test.ts
  • packages/clickhouse-datasource/src/datasource.ts
  • packages/clickhouse-datasource/src/discover-mv-schema.ts
  • packages/clickhouse-datasource/src/e2e.integration.test.ts
  • packages/clickhouse-datasource/src/query-traces.ts
  • packages/clickhouse-datasource/src/test/otel-ddl.ts
  • packages/core/src/denormalized-signals-zod.ts
  • packages/core/src/kopai-query-compiler.ts
  • packages/core/src/kopai-query.ts
  • packages/sdk/src/client.test.ts
  • packages/sdk/src/kopai-query-builder.test.ts
  • packages/sdk/src/request.ts
  • packages/sqlite-datasource/src/datasource-query.test.ts
  • packages/sqlite-datasource/src/datasource-read.test.ts
  • packages/sqlite-datasource/src/datasource-write.test.ts
  • packages/sqlite-datasource/src/db-datasource.ts
  • packages/sqlite-datasource/src/query-builder.test.ts
  • packages/sqlite-datasource/src/query-builder.ts
  • packages/ui-core/src/lib/component-catalog.test.ts
  • packages/ui/src/components/observability/DynamicDashboard/DynamicDashboard.test.tsx
  • packages/ui/src/components/observability/TraceTimeline/GraphView.tsx
  • packages/ui/src/components/observability/TraceTimeline/Minimap.tsx
  • packages/ui/src/components/observability/TraceTimeline/SpanDetailInline.tsx
  • packages/ui/src/components/observability/TraceTimeline/SpanRow.tsx
  • packages/ui/src/components/observability/TraceTimeline/TimelineBar.tsx
  • packages/ui/src/components/observability/TraceTimeline/index.tsx
  • packages/ui/src/components/observability/__fixtures__/trace-summaries.ts
  • packages/ui/src/components/observability/__fixtures__/traces.ts
  • packages/ui/src/components/observability/renderers/OtelMetricHistogram.tsx
  • packages/ui/src/components/observability/renderers/OtelMetricStat.tsx
  • packages/ui/src/components/observability/renderers/OtelMetricTable.tsx
  • packages/ui/src/components/observability/renderers/OtelMetricTimeSeries.tsx
  • packages/ui/src/components/observability/renderers/OtelTraceDetail.tsx
  • packages/ui/src/components/observability/renderers/narrowRows.test.ts
  • packages/ui/src/components/observability/renderers/narrowRows.ts
  • packages/ui/src/components/observability/types.ts
  • packages/ui/src/pages/observability.tsx
💤 Files with no reviewable changes (1)
  • packages/ui-core/src/lib/component-catalog.test.ts
✅ Files skipped from review due to trivial changes (3)
  • .changeset/ui-core-dedup.md
  • packages/ui/src/components/observability/types.ts
  • .changeset/sdk-error-detail-message.md
🚧 Files skipped from review as they are similar to previous changes (9)
  • packages/clickhouse-datasource/src/datasource-coerce.test.ts
  • packages/ui/src/components/observability/renderers/OtelMetricTable.tsx
  • packages/ui/src/components/observability/DynamicDashboard/DynamicDashboard.test.tsx
  • packages/ui/src/components/observability/renderers/OtelTraceDetail.tsx
  • packages/core/src/denormalized-signals-zod.ts
  • packages/sqlite-datasource/src/db-datasource.ts
  • packages/sdk/src/kopai-query-builder.test.ts
  • packages/sqlite-datasource/src/query-builder.ts
  • packages/sqlite-datasource/src/datasource-query.test.ts

Comment on lines +2003 to 2014
it("discoverMetrics provisions MVs on demand for a tenant without them", async () => {
// Tenant B has no discover MV tables — discoverMetrics must provision +
// backfill them in tenant B's database (not 500), then serve its own
// metrics only (tenant-isolated).
const tenantB = await ds.discoverMetrics({
requestContext: tenantBRequestContext(),
});
const names = tenantB.metrics.map((m) => m.name);
expect(names).toContain("tenant.b.gauge");
// Tenant A's metrics must NOT leak into tenant B's discovery.
expect(names).not.toContain("system.cpu.utilization");
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Resolve the contradictory discoverMetrics contract.

This test expects request-time MV provisioning, but Lines 1614-1714 explicitly assert the opposite contract: when discovery MVs are absent, discoverMetrics must stay read-only and fall back to a base-table scan. Both expectations cannot be true for the same method without an unshown tenant-specific branch, so one side of the suite is asserting the wrong behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/clickhouse-datasource/src/datasource.test.ts` around lines 2003 -
2014, The test suite has a contradictory contract for discoverMetrics: one test
(this block using tenantBRequestContext and discoverMetrics) expects runtime MV
provisioning, while other tests assert discoverMetrics must be read-only and
fall back to base-table scans when MVs are absent; pick one behavior and make
the suite consistent. To fix, either update this test to assert the read-only
fallback (remove expectations that MVs are provisioned and that tenant B gets
newly backfilled tables) or change the implementation of discoverMetrics to
perform tenant-scoped MV provisioning and update the other tests that assert
read-only behavior; locate usages of discoverMetrics and tenantBRequestContext
in the suite and align all assertions to the chosen contract. Ensure any test
that assumes provisioning explicitly mocks or sets the provisioning flag so
behavior is deterministic.

@Vunovati Vunovati force-pushed the feat/simplified-query branch from 1599cd0 to ad5ab71 Compare May 31, 2026 14:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant