镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

feat: browser event summary in row side panel - #3442

Open
SpencerTorres wants to merge 3 commits into
mainfrom
otel-browser-event-panel
Open

SpencerTorres wants to merge 3 commits into
mainfrom
otel-browser-event-panel

Conversation

@SpencerTorres

@SpencerTorres SpencerTorres commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Part of HDX-5736

Summary

Adds a browser event panel to the logs panel view. Newer OTel SDKs send these as logs, so this is a QoL change that adds clarity for logs that typically have no Body text

Changes

  • Section (BrowserEventSubpanel.tsx, DBRowOverviewPanel.tsx): "Browser event", open by default, after Exception.
    • Click: element, CSS selector, each data-otel-* attribute, page URL.
    • Navigation: URL, navigation type, same document, hash change. The flags read Yes/No from Map strings and JSON Bools.
    • Console: method, first line of the message, page URL.
    • Exceptions keep the Exception section and get no browser section.
  • Detection (utils/browserEvents.ts):
    • Only log rows are checked, so trace rows never match.
    • The event name decides: browser.user_action.click, browser.navigation, browser.console.
    • A row without an event name (the source has no Event Name Expression, or the table has no such column) falls back to the attribute keys the SDK sends only with each kind: browser.tag_name/browser.css_selector, browser.navigation.*, browser.console.method.
  • HTTP Request: hidden on rows that get a browser section, which in practice means navigations. Resource and navigation timing rows keep it, since they are fetches.
  • Empty body (DBRowSidePanelHeader.tsx, DBRowSidePanel.tsx): a new hideEmptyBody prop hides "No body for this event." on browser.* log rows. A non-empty Body still shows. Backend logs and exception rows with no Body keep the message.
  • Event name in the row lookup (DBRowDataPanel.tsx): no new query.
    • A bare column such as EventName is read from the row that SELECT * or the Known Columns List already returns, not selected. Older OTel log tables have no EventName column, and selecting it would fail the whole lookup.
    • Any other expression is selected as __hdx_event_name.
  • Where it shows: the Sessions drawer, the search side panel and inline expand, and the trace view.

Screenshots

Browser event section in log panel:
Browser event section in log panel

@SpencerTorres
SpencerTorres added this pull request to stack #3441 October 22, 2026 19:19
@changeset-bot

changeset-bot Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 7dad83d

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

This PR includes changesets to release 3 packages
Name Type
@hyperdx/app Patch
@hyperdx/api Patch
@hyperdx/otel-collector 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

@vercel

vercel Bot commented Oct 22, 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 Oct 30, 2026 1:39pm UTC
hyperdx-storybook Ready Ready Preview Oct 30, 2026 1:39pm UTC

Request Review

const eventNameExpr = isLogSource(source)
? source.eventNameExpression?.trim()
: undefined;
const eventNameColumn =

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.

🟠 major — A bare event-name column that is ALIAS or MATERIALIZED never reaches the row, so detection quietly falls back to attribute keys

ClickHouse leaves ALIAS and MATERIALIZED columns out of SELECT * unless asterisk_include_alias_columns/asterisk_include_materialized_columns is set. That setting is only added when the user turns on the off-by-default option (useSelectAllColumnsQuerySettings in hooks/useMaterializedAliasColumnsOption.ts). So a source with eventNameExpression: 'EventName' on a table where EventName is e.g. ALIAS LogAttributes['event.name'] gets row.EventName === undefined. Every row then goes through the attribute fallback: browser.resource_timing/web_vital rows show 'No body for this event.' and navigations missing the fallback keys keep the HTTP Request section. Fix: decide between reading and selecting from the table's column metadata (getMetadata().getColumns, select it under the alias only when the column exists, whatever its kind). Or, at minimum, select the bare column under __hdx_event_name when metadata shows it as an ALIAS/MATERIALIZED column. Add a test for the case.

Nothing blocks merge automatically, but a maintainer will expect this fixed if it is a real defect in code this PR changes. If it is about surrounding code, reply and say so instead of patching. Do not widen the PR. How to respond

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.

@SpencerTorres I think we should fix this

attributes={highlightedAttributeValues}
mainContent={mainContent}
mainContentHeader={mainContentColumn}
hideEmptyBody={

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 browser-row check for hideEmptyBody is written twice, in DBRowSidePanel and in RowOverviewPanel

DBRowSidePanelInner builds isLogSource(source) && isBrowserEventRow({eventName: normalizedRow[EVENT_NAME], attributes: normalizedRow[EVENT_ATTRIBUTES]}) inline. RowOverviewPanel (DBRowOverviewPanel.tsx:158-172) separately builds the same {eventName, attributes} row behind the same isLogSource gate. The side panel renders the header itself and passes hideHeader to the overview, so the two copies feed different headers and can drift apart. Fix: move it into one helper in utils/browserEvents.ts, e.g. isBrowserEventRowForSource(source, row) that reads __hdx_event_name/__hdx_event_attributes, and call it from both places.

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

@github-actions

github-actions Bot commented Oct 22, 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.

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

2 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.

@greptile-apps

greptile-apps Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The change affects browser log summaries across the app's row side-panel routes.

The new changes look safe, but the previously reported fixture-typing requirement must still be met before merging.

Fix All in Claude CodeFindings

  1. P2 Fixtures bypass type checks ▶

Summary

Adds browser-event summaries to row details and hides empty-body messages on browser logs.

  • Browser activity logs show a summary of each event.
  • Browser event logs skip the empty-body notice.

Reviews (9) · Last reviewed commit: "feat: elevate EventName in top level att..." · Reviewed by Greptile

Comment on lines +27 to +28
// `any`, not `as`, keeps this partial fixture off the lint warning budget.
const asSource = (value: any): TSource => value;

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.

P2 Fixtures bypass type checks

The new asSource helper accepts any and returns TSource, so incomplete or wrongly shaped fixtures pass without a type check. This violates the repository guide's directive to avoid any and use proper typing. Give the fixtures an explicit checked type before merging.

Context Used: AGENTS.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Deep Review

✅ No critical issues found. No P0/P1: rendering is React-escaped (no XSS), non-string bodies are coerced before use, parseJSON/isRecord/toAttributes guard malformed input, trace rows are gated behind isLogSource, and the bare-column regex keeps unvalidated identifiers out of the SELECT. The items below are recommended cleanups and nits.

🟡 P2 — recommended

  • packages/app/src/components/__tests__/DBRowOverviewPanel.browserEvent.test.tsx:31 — the asSource = (value: any): TSource => value helper lets partial/mis-shaped source fixtures pass with no type check, repeating a prior review comment that is still open while the sibling test already uses typed makeLogSource/makeTraceSource factories.
    • Fix: Replace asSource({...}) with the typed makeLogSource/makeTraceSource factories from @/llm/__fixtures__/sources and delete the any helper.
    • previous-comments, project-standards, kieran-typescript, testing
  • packages/app/src/components/DBRowSidePanel.tsx:1079 — browser-event detection and the hideEmptyBody gate are computed independently here and in DBRowOverviewPanel.tsx:160, using two different predicates (isBrowserEventRow inline vs browserEventKind != null), so the two sites can drift on the log-source guard, field mapping, or predicate.
    • Fix: Extract one shared helper that both call sites use to derive browser-event kind and the empty-body gate from a normalized row.
    • maintainability, adversarial
🔵 P3 nitpicks (6)
  • packages/app/src/utils/browserEvents.ts:233 — when a source has no event-name expression, every row hits the attribute-key fallback, so a non-browser log row that carries a browser.*-named attribute is mis-detected as a browser event, rendering a spurious panel and suppressing its (empty) body.
    • Fix: Require a browser. event-name prefix or a stronger multi-key signature before trusting the attribute-only fallback.
    • adversarial
  • packages/app/src/components/DBRowDataPanel.tsx:108 — a bare EventName column is read from the row rather than selected, so a source whose Known Columns List omits it (or a MATERIALIZED/ALIAS column) silently yields an undefined event name; name-only browser events then lose empty-body suppression while click/navigation/console still detect via attributes.
    • Fix: When a Known Columns List is active and does not include the bare column, fall back to selecting the expression under the alias, or document that EventName must be a plainly-projected column.
    • correctness, adversarial
  • packages/app/src/utils/browserEvents.ts:212 — the per-kind attribute-key lists in KIND_ATTRIBUTE_KEYS are duplicated by the literal keys in BrowserEventSubpanel.tsx (getClickRows/getNavigationRows/getConsoleRows), so an SDK/semconv rename must be applied in both files.
    • Fix: Hoist the shared attribute-key constants into browserEvents.ts and consume them from the subpanel.
    • maintainability
  • packages/app/src/components/BrowserEventSubpanel.tsx:71 — the kind dispatch is a non-exhaustive ternary that routes any future BrowserEventKind member to the console branch.
    • Fix: Use a switch with a default: const _exhaustive: never = kind so a new kind is a compile error.
    • kieran-typescript
  • packages/app/src/components/DBRowSidePanel.tsx:1080 — isBrowserEventRow({...}) is called inline in JSX, re-running flatten() over the event attributes on every render, unlike the memoized equivalent in DBRowOverviewPanel.
    • Fix: Wrap the computation in useMemo keyed on the normalized row.
    • adversarial
  • packages/app/src/components/DBRowOverviewPanel.tsx:165 — new code reads the string literal '__hdx_event_name' instead of the ROW_DATA_ALIASES.EVENT_NAME enum member added for exactly this alias.
    • Fix: Reference ROW_DATA_ALIASES.EVENT_NAME so an alias change cannot break the read silently.
    • maintainability

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

Testing gaps:

  • yesNo() unset→undefined branch and getConsoleRows undefined-body branch in BrowserEventSubpanel.tsx are uncovered.
  • getElementAttributes malformed/non-record JSON-string fallback (returns []) is untested.
  • DBRowSidePanel hideEmptyBody is not tested for a log source with no event name but positive attribute-fallback detection.
  • The attribute-key fallback false-positive path (non-browser row with a browser.* attribute) has no test.
  • The bare-column event-name path under a Known Columns List that omits the column is unverified.

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

@SpencerTorres
SpencerTorres force-pushed the otel-browser-event-panel branch from ef2d460 to 4bb67a0 Compare October 22, 2026 20:36
@github-actions github-actions Bot added the review/tier-2 Low risk — AI review + quick human skim label Oct 22, 2026
@github-actions

github-actions Bot commented Oct 22, 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: 6
  • Production lines changed: 237 (+ 510 in test files, excluded from tier calculation)
  • Branch: otel-browser-event-panel
  • Author: SpencerTorres

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 Oct 22, 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.

const eventNameExpr = isLogSource(source)
? source.eventNameExpression?.trim()
: undefined;
const eventNameColumn =

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 — Bare event name column is lost when * or the Known Columns List leaves it out

SELECT * skips MATERIALIZED and ALIAS columns unless the viewer option is on (useSelectAllColumnsQuerySettings in hooks/useMaterializedAliasColumnsOption.ts), and a Known Columns List may simply not include EventName. In either case row[eventNameColumn] is undefined, so web-vital or resource-timing rows (which have no fallback keys) still show "No body for this event.". To fix it, check that the column exists using the table metadata and select it under __hdx_event_name when it does, rather than reading it off *. If you keep the current approach, add a test for an expression that is set but missing from knownColumns.

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

['Message', body ? firstLine(body) : undefined],
['Page URL', read(attributes, PAGE_URL_KEY)],
];
}

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 — Navigation URL row skips the browser.document.url.full fallback the event label uses

getNavigationLabel in utils/browserEvents.ts reads ['url.full', 'browser.document.url.full'], but this row only reads url.full. On a navigation row that carries only the document URL, the list shows "Navigated /checkout" while the panel shows no URL. If the flags are also missing, RequestDetailsTable returns null and the section is an empty "Browser event" accordion, and HTTP Request is hidden too. Use the same firstSetString(attributes, ['url.full', PAGE_URL_KEY]) lookup, and don't render the accordion item when it has no rows.

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

attributes={highlightedAttributeValues}
mainContent={mainContent}
mainContentHeader={mainContentColumn}
hideEmptyBody={

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 — Two copies of the empty-body decision, one per header caller

DBRowSidePanel and RowOverviewPanel each rebuild isLogSource(source) && isBrowserEventRow({eventName, attributes}) from the same row aliases before rendering DBRowSidePanelHeader. The two copies must be kept in sync by hand, and a third header caller would miss the rule. Move the check into one shared helper that takes (source, row) (or into the header, which already gets rowData), so every caller uses the same rule.

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

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

E2E Test Results

✅ All tests passed • 461 passed • 1 skipped • 1837s

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

Tests ran across 4 shards in parallel.

View full report →

@SpencerTorres
SpencerTorres force-pushed the otel-browser-event-panel branch from 4bb67a0 to dc37768 Compare October 26, 2026 12:59
const eventNameExpr = isLogSource(source)
? source.eventNameExpression?.trim()
: undefined;
const eventNameColumn =

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 — A bare event-name column that is ALIAS or MATERIALIZED never reaches the row

SELECT * leaves out ALIAS and MATERIALIZED columns unless the opt-in asterisk_include_* settings are on (hooks/useMaterializedAliasColumnsOption.ts). A Known Columns List that doesn't name the column also drops it. In those cases row[eventNameColumn] is undefined, so browser.resource_timing and browser.web_vital rows lose detection and show "No body for this event." again. Fix: when the source's columns are known to contain the identifier (via Metadata), select it under __hdx_event_name. At minimum, use the row value only when it is present and fall back to selecting it otherwise.

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

['Message', body ? firstLine(body) : undefined],
['Page URL', read(attributes, PAGE_URL_KEY)],
];
}

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 — Navigation URL row ignores the browser.document.url.full fallback the event label uses

getNavigationLabel in utils/browserEvents.ts reads ['url.full', 'browser.document.url.full']. This subpanel reads only url.full, so when url.full is missing the event list shows "Navigated " but the Browser event section shows no URL. Use the same key list here, e.g. firstSetString(attributes, ['url.full', PAGE_URL_KEY]), ideally through one shared constant.

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

attributes={highlightedAttributeValues}
mainContent={mainContent}
mainContentHeader={mainContentColumn}
hideEmptyBody={

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 browser-row predicate is built in two places that must stay in sync

isLogSource(source) && isBrowserEventRow({ eventName, attributes }) is written inline here and again in the useMemo in DBRowOverviewPanel.tsx:158. Each copy picks the event-name key its own way: one uses ROW_DATA_ALIASES.EVENT_NAME, the other the literal __hdx_event_name. Move both into one helper such as isBrowserEventLogRow(source, row) in utils/browserEvents.ts and call it from both components.

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

)}

{requestPanelTitle != null && (
{browserEventKind != null && (

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 'Browser event' section can open with nothing in it

The section shows whenever browserEventKind != null, but RequestDetailsTable (RequestDetailsTable.tsx:8) returns null when every row value is unset. A log source with an Event Name Expression but no eventAttributesExpression hits this: a browser.user_action.click row gets an expanded, empty 'Browser event' section. Build the rows in RowOverviewPanel, or have BrowserEventSubpanel report whether it has content, and render the Accordion.Item only when at least one row is set.

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

attributes={highlightedAttributeValues}
mainContent={mainContent}
mainContentHeader={mainContentColumn}
hideEmptyBody={

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 'is this a browser log row' check is written out in two places

DBRowSidePanel repeats isLogSource(source) && isBrowserEventRow({eventName, attributes}) from RowOverviewPanel (DBRowOverviewPanel.tsx:158-172) to decide hideEmptyBody for the same header. The two copies can drift, for example if one gains a source-kind check and the other does not. Add one helper to utils/browserEvents.ts, such as isBrowserEventLogRow(source, row), and call it from both places.

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

const eventNameExpr = isLogSource(source)
? source.eventNameExpression?.trim()
: undefined;
const eventNameColumn =

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 — A bare EventName that is an ALIAS or MATERIALIZED column is never read

A bare identifier is only read from the SELECT * result. ClickHouse leaves ALIAS and MATERIALIZED columns out of * unless the asterisk_include_* settings are on, and useSelectAllColumnsQuerySettings (hooks/useMaterializedAliasColumnsOption.ts:46) only turns them on behind a user toggle. So an EventName ... ALIAS LogAttributes['event.name'] column gives an undefined event name. Detection then falls back to attribute keys, and browser.resource_timing and browser.web_vital rows show 'No body for this event.' again. Either read the column from the row only when data.meta lists it and select it under the alias otherwise, or note the limitation in the comment.

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

const eventNameExpr = isLogSource(source)
? source.eventNameExpression?.trim()
: undefined;
const eventNameColumn =

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 — A bare event-name column that is MATERIALIZED or ALIAS is never read

SELECT * leaves out MATERIALIZED/ALIAS columns unless the opt-in setting in hooks/useMaterializedAliasColumnsOption.ts is on. So with EventName ... MATERIALIZED LogAttributes['event.name'], row[eventNameColumn] is undefined and every non-click/nav/console browser.* row (web vitals, resource timing) loses its event name, so hideEmptyBody stays off for it. Fix: only take the bare-column shortcut when the column is known to come back from the row query (check the column kind via metadata, or check knownColumns). Otherwise select it under __hdx_event_name. Add a test for the case where the row has no such key but the column exists.

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

attributes={highlightedAttributeValues}
mainContent={mainContent}
mainContentHeader={mainContentColumn}
hideEmptyBody={

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 — Browser-row detection with the log-source gate is duplicated in two components

isLogSource(source) && isBrowserEventRow({eventName: row.__hdx_event_name, attributes: row.__hdx_event_attributes}) is now built separately here and in DBRowOverviewPanel.tsx:159-173. Both feed the same DBRowSidePanelHeader, which already receives rowData. Move this into one place so the two call sites can't drift. Either add a helper in utils/browserEvents.ts that takes (source, normalizedRow), or have the header work it out from rowData plus a source/isLogSource prop.

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

@karl-power karl-power 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.

Just one comment here but otherwise looks good

This branch was successfully deployed

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

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants