Skip to content

fix: selecting an at-prefixed JSON key no longer breaks row details - #3520

Merged
kodiakhq[bot] merged 2 commits into
mainfrom
cursor/fix-at-prefixed-json-key-row-details-4626
Nov 4, 2026
Merged

kodiakhq[bot] merged 2 commits into
mainfrom
cursor/fix-at-prefixed-json-key-row-details-4626

Conversation

@pulpdrew

@pulpdrew pulpdrew commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes #3519

Selecting a JSON subcolumn whose key is not a bare identifier — e.g. event.`@request_id` — made the row side panel come up blank.

ClickHouse reports the result column name for such a select without backticks (event.@request_id). The row side panel rebuilds a WHERE clause from the displayed result columns to fetch the full row (useRowWhere → quoteResultColumnNameIfNeeded). That helper left any dotted name untouched, so the detail query referenced event.@request_id raw — where @request_id is not a valid bare identifier — which matched zero rows and left the panel empty.

The helper now splits a plain dotted result-column name on . and quotes each segment that isn't a bare identifier (event.@request_id, event.200). Valid paths like json.a.b are unchanged. JSON type casts and sub-object accessors, which ClickHouse already reports backticked (col.path.:String, col.^sub), are kept as is. Names that aren't plain paths, like function calls and literals, are still left verbatim.

Screenshots or video

The change is in the row detail side panel. "Before" is the empty panel the broken detail query produces; "After" is the same panel populated with the selected event (verified by the E2E test below — it fails on main and passes on this branch).

Before After
Row details empty with the fix reverted Same panel, populated — asserted by json-at-prefixed-key-row-details.spec.ts

How to reproduce

Starting point: full-stack yarn dev (needs a JSON-column table), or the E2E E2E Interesting Filter Keys source seeded by this PR.

Schema/seed:

CREATE TABLE default.hyperdx_row_repro
(
  timestamp DateTime('UTC'),
  event JSON(max_dynamic_paths=0, `@request_id` Nullable(String))
)
ENGINE = MergeTree PARTITION BY toDate(timestamp) ORDER BY timestamp;

INSERT INTO default.hyperdx_row_repro VALUES
('2026-11-02 12:53:33', '{"@request_id":"request-A"}');

On main:

  1. Create a log source for the table, Timestamp Column = timestamp.
  2. Set the time range to cover the seeded row.
  3. Set SELECT to timestamp, event.`@request_id`.
  4. Open the row details → panel is blank (the detail query returns rows: 0).

On this branch:

  1. Same steps → the row details panel loads the selected event.

How to test on Vercel preview

N/A — the fix needs a JSON-column schema with a seeded row, which the demo server does not provide. Covered by the full-stack E2E test instead.

References

  • Linear Issue: Closes HDX-5867

@pulpdrew
pulpdrew requested a review from a team as a code owner November 2, 2026 15:15
@pulpdrew
pulpdrew requested a review from wrn14897 November 2, 2026 15:15
@vercel

vercel Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
hyperdx-oss Ready Ready Preview Nov 4, 2026 12:06pm UTC
hyperdx-storybook Ready Ready Preview Nov 4, 2026 12:06pm UTC

Request Review

@changeset-bot

changeset-bot Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f2f940c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@hyperdx/common-utils Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added the review/tier-2 Low risk — AI review + quick human skim label Nov 2, 2026
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

🔵 Tier 2 — Low Risk

Small, isolated change with no API route or data model modifications.

Why this tier:

  • Standard feature/fix — introduces new logic or modifies core functionality

Review process: AI review + quick human skim (target: 5–15 min). Reviewer validates AI assessment and checks for domain-specific concerns.
SLA: Resolve within 4 business hours.

Stats
  • Production files changed: 1
  • Production lines changed: 47 (+ 166 in test files, excluded from tier calculation)
  • Branch: cursor/fix-at-prefixed-json-key-row-details-4626
  • Author: pulpdrew

To override this classification, remove the review/tier-2 label and apply a different review/tier-* label. Manual overrides are preserved on subsequent pushes.

@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Duplicate code analysis

No new duplicate code introduced by this PR.


jscpd compared this branch against origin/main
across app, api and common-utils. Only new clones are listed; the codebase
currently holds 114 in total (1.40%).
Run yarn dupes locally to reproduce, or yarn dupes:all for the full picture.

@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

PR Review

If you are a coding agent acting for the author, read this first.
Nothing below blocks merge automatically; a maintainer decides. What they will expect:

  • 🔴 critical or 🟠 major in code this PR adds or changes: fix before asking for review.
  • 🔵 minor in code this PR changes: your call. Fix if small, otherwise reply.
  • Anything about surrounding code, or asking you to widen the change (hoist a helper,
    dedupe with another file, fix other call sites): never fix here, whatever the
    severity. Reply with one sentence; if it is critical, say so plainly so a human sees it.

One commit per review round. After two rounds, stop and ask a maintainer to review
scope rather than addressing more automated findings. Full rule: AGENTS.md.

1 finding(s): 🔴 0 critical · 🟠 0 major · 🔵 1 minor

1 posted as inline comment(s) on the changed lines.


Severity is the reviewer's own estimate and is used for ordering, not filtering. No finding blocks merge automatically; a maintainer decides.

@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Deep Review

Scope: git diff d08b2fa737967b3cc40a24e460f9539b0087fc50 — one production function group in packages/common-utils/src/core/metadata.ts (quoteResultColumnNameIfNeeded, splitResultColumnPath, quotePathSegment, PLAIN_PATH_SEGMENT, OPERATOR_PATH_SEGMENT), plus unit tests, an E2E spec, seed data, and a page object.

Intent: Quote non-bare JSON path segments when rebuilding the row-detail WHERE clause so selecting a key like event.`@request_id` (reported by ClickHouse as the bare event.@request_id) no longer produces a zero-row detail query.

✅ No critical issues found.

The change is tight and well-constrained. The new segmentation correctly preserves the prior verbatim behavior for the cases that mattered (bare paths like json.a.b, function calls, literals, bracket accessors, backtick-leading names) and only rewrites plain dotted paths — the exact inputs that were broken. The three consumer call sites (packages/cli/src/shared/useRowWhere.ts:158, packages/app/src/components/DBTable/adhocCellCondition.ts:49, packages/app/src/hooks/useResultColumnFilterKeys.ts:114) all benefit identically from the shared fix with no regression, since dotted names previously passed through verbatim in every one of them. The while (true) loop provably terminates (each iteration consumes ≥1 character or returns), and the two regexes avoid nested-quantifier backtracking. Unit coverage is unusually thorough for the new branches, and the E2E exercises the real UI path and would fail on main.

🟡 P2 — recommended

  • packages/app/tests/e2e/features/search/json-at-prefixed-key-row-details.spec.ts:49 — the new E2E covers only the useRowWhere detail-panel path; the two other consumers of the changed helper (click-to-filter via adhocCellCondition.ts and filter keys via useResultColumnFilterKeys.ts) get the same @-prefixed-key behavior change but no direct coverage.
    • Fix: add or extend an E2E/integration assertion that exercises click-to-filter or filter-key building on an at-prefixed JSON key so a future regression in those paths is caught.
🔵 P3 nitpicks (1)
  • packages/common-utils/src/__tests__/metadata.test.ts:4130 — the unit suite covers trailing type casts and sub-object accessors but not an operator segment in a non-trailing position (e.g. a mid-path .:Int. cast or .^a.^b``), which the implementation handles distinctly from the trailing case.
    • Fix: add a case asserting a mid-path operator segment round-trips correctly to lock in the non-trailing branch.

Reviewers (10): correctness, security, adversarial, testing, maintainability, kieran-typescript, project-standards, previous-comments, agent-native, learnings-researcher.

Testing gaps: E2E coverage is limited to the row-detail path; the click-to-filter and filter-key consumers of the changed helper are exercised only indirectly through the unit tests.

No finding blocks merge automatically. A maintainer will expect P0/P1 findings in code this PR changes to be fixed; P2/P3 are your call -- fix or reply. Never fix findings about surrounding code here; reply instead. Do not widen the PR. How to respond

@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

E2E Test Results

✅ All tests passed • 462 passed • 1 skipped • 1416s

Status Count
✅ Passed 462
❌ Failed 0
⚠️ Flaky 1
⏭️ Skipped 1

Tests ran across 4 shards in parallel.

View full report →

@jordan-simonovski jordan-simonovski left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Absolute cinema. No notes.

await expect(searchPage.sidePanel.container).toBeVisible();
// Before the fix the detail WHERE dropped the key's backticks and
// matched no rows, so the panel rendered empty with no error.
await expect(searchPage.sidePanel.errorState).toHaveCount(0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 minor — The errorState toHaveCount(0) check runs before the row query finishes and can't catch the bug

Delete the assertion, or move it after the columnValue(ROW1.jsonAtKeyValue) visibility check. As written it passes as soon as the panel opens, while the detail query is still pending. Before the fix the panel also showed no error, only an empty result, so this line never separates broken from fixed. The columnValue assertion is the one actually testing the fix.

Advisory. Fix if it is a small defect in code this PR changes; otherwise reply in the thread. Do not widen the PR or touch files it did not already change. How to respond

@kodiakhq
kodiakhq Bot merged commit 22f824c into main Nov 4, 2026
28 checks passed
@kodiakhq
kodiakhq Bot deleted the cursor/fix-at-prefixed-json-key-row-details-4626 branch November 4, 2026 12:08

This branch was successfully deployed

2 active deployments
Preview – hyperdx-oss — f2f940c0 Deployed Nov 4, 2026 by vercel[bot]
Preview – hyperdx-storybook — f2f940c0 Deployed Nov 4, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automerge review/tier-2 Low risk — AI review + quick human skim

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Selecting an at-prefixed JSON key breaks row details

2 participants