Skip to content

feat(eap): semver sort key for sentry.release ORDER BY in EAP#8103

Open
phacops wants to merge 10 commits into
masterfrom
claude/semver-sorting-eap-clickhouse-lpg3gs
Open

feat(eap): semver sort key for sentry.release ORDER BY in EAP#8103
phacops wants to merge 10 commits into
masterfrom
claude/semver-sorting-eap-clickhouse-lpg3gs

Conversation

@phacops

@phacops phacops commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes incorrect lexicographic ordering of sentry.release strings when used in ORDER BY (and GROUP BY) in EAP trace item table queries.

Bugs fixed:

  • 1.2.10 was sorting before 1.2.9 (classic lex bug)
  • 1.2.3-beta.1 was sorting after 1.2.3 (pre-release should come before stable)
  • 1.2 and 1.2.0 were not equal (length mismatch)

Approach: Wrap sentry.release in a tuple(arrayResize(arrayMap(x -> toUInt32OrZero(x), splitByChar('.', release_part)), 4), is_stable) sort key when it appears in ORDER BY / GROUP BY. Uses only ClickHouse functions available on Altinity 25.3/25.8 — no naturalSortKey (requires upstream 26.3+) and no COLLATE (fails pre-release ordering, needs DangerousRawSQL).

Key correctness properties:

  • 1.2.9 before 1.2.10 (numeric component comparison) ✓
  • 1.2.3-beta.1 before 1.2.3 (pre-release sorts before stable) ✓
  • 1.2.3-beta.1 after 1.2.2 (pre-release of newer > older stable) ✓
  • 1.2 == 1.2.0 (arrayResize pads to 4 components) ✓
  • [email protected] strips the @-prefix before comparison ✓
  • 4-component versions like 25.3.8.999 before 25.3.8.10041

Changes

File Change
snuba/web/rpc/common/common.py Add semver_sort_key() helper and _SEMVER_COMPONENT_COUNT constant
snuba/web/rpc/v1/resolvers/R_eap_items/resolver_trace_item_table.py Add _SEMVER_SORT_ATTRIBUTES; extend _groupby_order_by_expression() to wrap sentry.release in semver_sort_key()
tests/web/rpc/test_common.py Unit tests for semver_sort_key() expression structure
tests/web/rpc/v1/test_endpoint_trace_item_table/test_endpoint_trace_item_table.py Integration tests verifying sort order with ClickHouse

Test plan

  • Unit tests: TestSemverSortKey — checks expression shape (no DB required)
  • Integration tests: TestSemverSorting — writes spans with different sentry.release values, queries with ORDER BY sentry.release ASC/DESC and asserts:
    • 1.2.9 before 1.2.10
    • 1.2.3-beta.1 before 1.2.3
    • 1.2.3-beta.1 after 1.2.2
    • [email protected] sorts as version 2.0.0
    • 1.2 and 1.2.0 are adjacent (equal sort key)
    • DESC is exact reverse of ASC

🤖 Generated with Claude Code

https://claude.ai/code/session_013TCwndq43WTDRf6jsERQHN


Generated by Claude Code

Fixes lexicographic ordering of release strings by wrapping
`sentry.release` in a `tuple(arrayResize(arrayMap(...), 4), is_stable)`
sort key when used in ORDER BY / GROUP BY in EAP trace item table
queries. This ensures:

- 1.2.9 sorts before 1.2.10 (numeric, not lexicographic)
- 1.2.3-beta.1 sorts before 1.2.3 (prerelease before stable)
- 1.2.3-beta.1 sorts after 1.2.2 (prerelease of newer > older stable)
- 1.2 and 1.2.0 are equal (arrayResize pads to 4 components)
- package@version strips the prefix before comparison

Uses only ClickHouse functions available on Altinity 25.3/25.8
(no naturalSortKey which requires upstream 26.3+).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_013TCwndq43WTDRf6jsERQHN
@phacops phacops requested review from a team as code owners June 25, 2026 03:07
Comment thread snuba/web/rpc/v1/resolvers/R_eap_items/resolver_trace_item_table.py
Comment thread snuba/web/rpc/v1/resolvers/R_eap_items/resolver_trace_item_table.py
claude and others added 2 commits June 25, 2026 03:23
Two fixes for the semver sort key implementation:

1. Replace f.tuple(..., alias=alias) with FunctionCall(alias, "tuple", ...)
   to fix mypy "Optional[str] not compatible with str" error on the alias
   argument.

2. Only apply semver_sort_key in the ORDER BY path, not GROUP BY.
   GROUP BY sentry.release must use the raw attribute expression so that
   the SELECT (also the raw string) is a function of the GROUP BY key and
   ClickHouse accepts the aggregation query. ORDER BY on a function of a
   GROUP BY key is valid in ClickHouse, so semver ordering still works.
   This also fixes the 500 error in Sentry's test_semver_build test where
   the spans events API auto-groups by release.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_013TCwndq43WTDRf6jsERQHN

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4be96cd. Configure here.

Comment thread snuba/web/rpc/v1/resolvers/R_eap_items/resolver_trace_item_table.py Outdated
claude added 3 commits June 25, 2026 03:32
…rison

The flextime pagination filter was comparing the raw release string
lexicographically, while ORDER BY now uses the semver tuple key.  This
caused rows to be skipped or repeated on follow-up pages when
`sentry.release` was in the order clause (e.g. "1.2.3-beta.1" would be
missed because it sorts after "1.2.3" lexicographically but before it
semantically).

Fix: move `SEMVER_SORT_ATTRIBUTES` to common.py so pagination.py can
import it.  In `get_filters`, wrap both the column reference and the
stored literal value in `semver_sort_key(...)` for any semver attribute
so the page-boundary `<` comparison uses the same ordering as ORDER BY.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_013TCwndq43WTDRf6jsERQHN
sentry.release is coalesced from multiple attribute columns
(attributes_string_25['sentry.release'] + attributes_string_30['release']),
which makes the expression Nullable(String).  ClickHouse forbids
Nullable(Array(...)), so splitByChar on the raw expression would throw:
  Code: 43 – Nested type Array(String) cannot be inside Nullable type

Fix: apply ifNull(expr, '') at the start of semver_sort_key to convert
Nullable(String) to String before any string→array operations.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_013TCwndq43WTDRf6jsERQHN
"1.2" and "1.2.0" normalise to the same sort key ([1,2,0,0], 1).
ClickHouse may return them in either relative order within the tied
pair, making the strict `asc == list(reversed(desc))` assertion
non-deterministic.  Collapse contiguous tied elements into a frozenset
before comparing so the test is order-insensitive within ties while
still verifying that every other element is in exact reverse order.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_013TCwndq43WTDRf6jsERQHN
@phacops phacops marked this pull request as draft June 25, 2026 23:18
claude and others added 4 commits June 26, 2026 20:46
Resolve conflict in resolver_trace_item_table.py:
- Keep master's updated _groupby_order_by_expression docstring (TYPE_ARRAY
  note) plus the semver paragraph.
- Keep master's inlined _convert_order_by structure and use_array_map_columns
  aggregation arg while preserving for_order_by=True so SEMVER_SORT_ATTRIBUTES
  still get the semver tuple sort key in ORDER BY.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_013TCwndq43WTDRf6jsERQHN
Master's ruff config enables flake8-bugbear; B905 requires an explicit
strict= argument on zip(). column_names and column_values are built in
lockstep so strict=True is correct (they always have equal length).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_013TCwndq43WTDRf6jsERQHN
Resolve conflict in test_endpoint_trace_item_table.py: both branches
appended independent test code at end of file. Keep both the
TestSemverSorting class and master's
test_uniq_with_default_value_double_casts_to_float64.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_013TCwndq43WTDRf6jsERQHN
@phacops phacops marked this pull request as ready for review June 28, 2026 21:10
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.

2 participants