Skip to content

[NA] debug deploy#3

Closed
haarcuba wants to merge 1 commit intomainfrom
debug_deploy
Closed

[NA] debug deploy#3
haarcuba wants to merge 1 commit intomainfrom
debug_deploy

Conversation

@haarcuba
Copy link
Copy Markdown
Contributor

No description provided.

@haarcuba haarcuba closed this May 18, 2023
@andrescrz andrescrz deleted the debug_deploy branch September 2, 2024 11:35
thiagohora added a commit that referenced this pull request Nov 4, 2025
- #7: Add INSTANCE singleton pattern for InstantConverter
- #8: Use StringUtils.isEmpty() for null-safe empty check
- Note: #2 and #3 already addressed in previous commit
thiagohora added a commit that referenced this pull request Nov 4, 2025
- #7: Add INSTANCE singleton pattern for InstantConverter
- #8: Use StringUtils.isEmpty() for null-safe empty check
- Note: #2 and #3 already addressed in previous commit
thiagohora added a commit that referenced this pull request Nov 4, 2025
)

* [NA] [BE] Upgrade MySQL container from Testcontainers

* Fix imports order

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for traces

- Add InstantToUUIDMapper to convert Instant timestamps to UUIDv7 bounds
- Add InstantParamConverter to parse ISO-8601 and epoch millisecond time parameters
- Update TracesResource to accept from_time and to_time parameters on /traces and /traces/stats endpoints
- Update TraceDAO to apply UUID-based time filtering using BETWEEN clause on id column
- Update TraceSearchCriteria to include uuidFromTime and uuidToTime fields
- Add comprehensive integration tests for time filtering with boundary conditions
- All tests passing: 10/10 time filtering tests + validation tests

* [OPIK-2856] Address PR review comments: improve exception handling and type safety

- Fix InstantParamConverter to catch specific DateTimeParseException instead of generic Exception
- Add debug logging when falling back to epoch milliseconds parsing
- Refactor anonymous ParamConverter class to named InstantConverter inner class for clarity
- Suppress unchecked cast with @SuppressWarnings annotation
- Fix MySQLContainerUtils return type to use MySQLContainer<?> for type safety

* [OPIK-2856] Fix InstantToUUIDMapperTest to match implementation

- Update tests to reflect that toUpperBound uses next millisecond (+1ms) for inclusive BETWEEN queries
- Remove outdated assertions expecting same timestamp in both bounds
- Verify upper bound is lexicographically greater than lower bound
- All 13 tests now passing

* Remove setup duplicated code

* Revision 2: Address PR review comments - LOW priority fixes

- #7: Add INSTANCE singleton pattern for InstantConverter
- #8: Use StringUtils.isEmpty() for null-safe empty check
- Note: #2 and #3 already addressed in previous commit

* Revision 3: Use IdGenerator.getTimeOrderedEpoch() for UUID bounds

- Simplified InstantToUUIDMapper to use IdGenerator.getTimeOrderedEpoch() instead of convertOtelIdToUUIDv7
- Per UUIDv7 RFC, sub-millisecond 12 bits are optional with millisecond granularity
- Start/end interval semantics with ±1ms ensures correct BETWEEN query results
- This approach has been battle-tested for months without issues per reviewer recommendation
- Converted InstantToUUIDMapper to @singleton service for proper DI integration
- Updated TracesResource to inject InstantToUUIDMapper dependency
- Updated tests to properly mock IdGenerator dependency

* Fix tests
thiagohora added a commit that referenced this pull request Nov 4, 2025
* [NA] [BE] Upgrade MySQL container from Testcontainers

* Fix imports order

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for traces

- Add InstantToUUIDMapper to convert Instant timestamps to UUIDv7 bounds
- Add InstantParamConverter to parse ISO-8601 and epoch millisecond time parameters
- Update TracesResource to accept from_time and to_time parameters on /traces and /traces/stats endpoints
- Update TraceDAO to apply UUID-based time filtering using BETWEEN clause on id column
- Update TraceSearchCriteria to include uuidFromTime and uuidToTime fields
- Add comprehensive integration tests for time filtering with boundary conditions
- All tests passing: 10/10 time filtering tests + validation tests

* [OPIK-2856] Address PR review comments: improve exception handling and type safety

- Fix InstantParamConverter to catch specific DateTimeParseException instead of generic Exception
- Add debug logging when falling back to epoch milliseconds parsing
- Refactor anonymous ParamConverter class to named InstantConverter inner class for clarity
- Suppress unchecked cast with @SuppressWarnings annotation
- Fix MySQLContainerUtils return type to use MySQLContainer<?> for type safety

* [OPIK-2856] Fix InstantToUUIDMapperTest to match implementation

- Update tests to reflect that toUpperBound uses next millisecond (+1ms) for inclusive BETWEEN queries
- Remove outdated assertions expecting same timestamp in both bounds
- Verify upper bound is lexicographically greater than lower bound
- All 13 tests now passing

* Remove setup duplicated code

* Revision 2: Address PR review comments - LOW priority fixes

- #7: Add INSTANCE singleton pattern for InstantConverter
- #8: Use StringUtils.isEmpty() for null-safe empty check
- Note: #2 and #3 already addressed in previous commit

* Revision 3: Use IdGenerator.getTimeOrderedEpoch() for UUID bounds

- Simplified InstantToUUIDMapper to use IdGenerator.getTimeOrderedEpoch() instead of convertOtelIdToUUIDv7
- Per UUIDv7 RFC, sub-millisecond 12 bits are optional with millisecond granularity
- Start/end interval semantics with ±1ms ensures correct BETWEEN query results
- This approach has been battle-tested for months without issues per reviewer recommendation
- Converted InstantToUUIDMapper to @singleton service for proper DI integration
- Updated TracesResource to inject InstantToUUIDMapper dependency
- Updated tests to properly mock IdGenerator dependency

* Fix tests

* [OPIK-2856] [BE] Split Get spans Tests

* Fix format
thiagohora added a commit that referenced this pull request Nov 5, 2025
* [NA] [BE] Upgrade MySQL container from Testcontainers

* Fix imports order

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for traces

- Add InstantToUUIDMapper to convert Instant timestamps to UUIDv7 bounds
- Add InstantParamConverter to parse ISO-8601 and epoch millisecond time parameters
- Update TracesResource to accept from_time and to_time parameters on /traces and /traces/stats endpoints
- Update TraceDAO to apply UUID-based time filtering using BETWEEN clause on id column
- Update TraceSearchCriteria to include uuidFromTime and uuidToTime fields
- Add comprehensive integration tests for time filtering with boundary conditions
- All tests passing: 10/10 time filtering tests + validation tests

* [OPIK-2856] Address PR review comments: improve exception handling and type safety

- Fix InstantParamConverter to catch specific DateTimeParseException instead of generic Exception
- Add debug logging when falling back to epoch milliseconds parsing
- Refactor anonymous ParamConverter class to named InstantConverter inner class for clarity
- Suppress unchecked cast with @SuppressWarnings annotation
- Fix MySQLContainerUtils return type to use MySQLContainer<?> for type safety

* [OPIK-2856] Fix InstantToUUIDMapperTest to match implementation

- Update tests to reflect that toUpperBound uses next millisecond (+1ms) for inclusive BETWEEN queries
- Remove outdated assertions expecting same timestamp in both bounds
- Verify upper bound is lexicographically greater than lower bound
- All 13 tests now passing

* Remove setup duplicated code

* Revision 2: Address PR review comments - LOW priority fixes

- #7: Add INSTANCE singleton pattern for InstantConverter
- #8: Use StringUtils.isEmpty() for null-safe empty check
- Note: #2 and #3 already addressed in previous commit

* Revision 3: Use IdGenerator.getTimeOrderedEpoch() for UUID bounds

- Simplified InstantToUUIDMapper to use IdGenerator.getTimeOrderedEpoch() instead of convertOtelIdToUUIDv7
- Per UUIDv7 RFC, sub-millisecond 12 bits are optional with millisecond granularity
- Start/end interval semantics with ±1ms ensures correct BETWEEN query results
- This approach has been battle-tested for months without issues per reviewer recommendation
- Converted InstantToUUIDMapper to @singleton service for proper DI integration
- Updated TracesResource to inject InstantToUUIDMapper dependency
- Updated tests to properly mock IdGenerator dependency

* Fix tests

* [OPIK-2856] [BE] Split Get spans Tests

* Fix format

* Revision 2: Extract duplicated span creation logic into createSpanWithTimestamp helper method

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for spans

* Revision 3: Extract workspace setup duplication into setupTestWorkspace helper method and fix transformTestParams call
thiagohora added a commit that referenced this pull request Nov 5, 2025
…d of direct URL_TEMPLATE calls (#3947)

* [NA] [BE] Upgrade MySQL container from Testcontainers

* Fix imports order

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for traces

- Add InstantToUUIDMapper to convert Instant timestamps to UUIDv7 bounds
- Add InstantParamConverter to parse ISO-8601 and epoch millisecond time parameters
- Update TracesResource to accept from_time and to_time parameters on /traces and /traces/stats endpoints
- Update TraceDAO to apply UUID-based time filtering using BETWEEN clause on id column
- Update TraceSearchCriteria to include uuidFromTime and uuidToTime fields
- Add comprehensive integration tests for time filtering with boundary conditions
- All tests passing: 10/10 time filtering tests + validation tests

* [OPIK-2856] Address PR review comments: improve exception handling and type safety

- Fix InstantParamConverter to catch specific DateTimeParseException instead of generic Exception
- Add debug logging when falling back to epoch milliseconds parsing
- Refactor anonymous ParamConverter class to named InstantConverter inner class for clarity
- Suppress unchecked cast with @SuppressWarnings annotation
- Fix MySQLContainerUtils return type to use MySQLContainer<?> for type safety

* [OPIK-2856] Fix InstantToUUIDMapperTest to match implementation

- Update tests to reflect that toUpperBound uses next millisecond (+1ms) for inclusive BETWEEN queries
- Remove outdated assertions expecting same timestamp in both bounds
- Verify upper bound is lexicographically greater than lower bound
- All 13 tests now passing

* Remove setup duplicated code

* Revision 2: Address PR review comments - LOW priority fixes

- #7: Add INSTANCE singleton pattern for InstantConverter
- #8: Use StringUtils.isEmpty() for null-safe empty check
- Note: #2 and #3 already addressed in previous commit

* Revision 3: Use IdGenerator.getTimeOrderedEpoch() for UUID bounds

- Simplified InstantToUUIDMapper to use IdGenerator.getTimeOrderedEpoch() instead of convertOtelIdToUUIDv7
- Per UUIDv7 RFC, sub-millisecond 12 bits are optional with millisecond granularity
- Start/end interval semantics with ±1ms ensures correct BETWEEN query results
- This approach has been battle-tested for months without issues per reviewer recommendation
- Converted InstantToUUIDMapper to @singleton service for proper DI integration
- Updated TracesResource to inject InstantToUUIDMapper dependency
- Updated tests to properly mock IdGenerator dependency

* Fix tests

* [OPIK-2856] [BE] Split Get spans Tests

* Fix format

* Revision 2: Extract duplicated span creation logic into createSpanWithTimestamp helper method

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for spans

* Revision 3: Extract workspace setup duplication into setupTestWorkspace helper method and fix transformTestParams call

* [OPIK-2856] Refactor TracesResourceTest to use TraceResourceClient instead of direct URL_TEMPLATE calls

- Replace all direct client.target(URL_TEMPLATE) calls with TraceResourceClient methods
- Add callFeedbackScoresWithCookie method to TraceResourceClient for session token authentication
- Add callRetrieveThreadResponseWithCookie method to TraceResourceClient for session token authentication
- Fix feedback batch endpoint by using callFeedbackScores and callFeedbackScoresWithCookie
- Add null checks for query parameters to prevent NPE errors
- Fix API key vs session token usage in authentication tests
- Rename get__whenApiKeyIsPresent__thenReturnTraceThread to get__whenSessionTokenIsPresent__thenReturnTraceThread in SessionTokenCookie class
- Add mockGetWorkspaceIdByName() calls for proper workspace mocking
- Preserve original test assertions and behavior
- All tests properly refactored to use resource client methods instead of direct HTTP calls

* [OPIK-2856] Remove duplicate methods from TraceResourceClient

- Remove callGetTraces() - duplicate of callGetTracesWithQueryParams()
- Remove callSearchTraces() - duplicate of callSearchTracesStream()
- Reduced code duplication and maintenance burden

* Fix tests

* Revision 2: Address Copilot review comments - remove redundant wrapper method and add clarifying comment

* Revision 3: Extract duplicated path splitting logic into helper method addPathSegments()

* Revision 4: Make getWebTarget() private and add callGetTraceThreadsWithSorting() public method

* Revision 7: Move addPathSegments() and addQueryParameters() helper methods to BaseCommentResourceClient
thiagohora added a commit that referenced this pull request Nov 6, 2025
…3953)

* [NA] [BE] Upgrade MySQL container from Testcontainers

* Fix imports order

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for traces

- Add InstantToUUIDMapper to convert Instant timestamps to UUIDv7 bounds
- Add InstantParamConverter to parse ISO-8601 and epoch millisecond time parameters
- Update TracesResource to accept from_time and to_time parameters on /traces and /traces/stats endpoints
- Update TraceDAO to apply UUID-based time filtering using BETWEEN clause on id column
- Update TraceSearchCriteria to include uuidFromTime and uuidToTime fields
- Add comprehensive integration tests for time filtering with boundary conditions
- All tests passing: 10/10 time filtering tests + validation tests

* [OPIK-2856] Address PR review comments: improve exception handling and type safety

- Fix InstantParamConverter to catch specific DateTimeParseException instead of generic Exception
- Add debug logging when falling back to epoch milliseconds parsing
- Refactor anonymous ParamConverter class to named InstantConverter inner class for clarity
- Suppress unchecked cast with @SuppressWarnings annotation
- Fix MySQLContainerUtils return type to use MySQLContainer<?> for type safety

* [OPIK-2856] Fix InstantToUUIDMapperTest to match implementation

- Update tests to reflect that toUpperBound uses next millisecond (+1ms) for inclusive BETWEEN queries
- Remove outdated assertions expecting same timestamp in both bounds
- Verify upper bound is lexicographically greater than lower bound
- All 13 tests now passing

* Remove setup duplicated code

* Revision 2: Address PR review comments - LOW priority fixes

- #7: Add INSTANCE singleton pattern for InstantConverter
- #8: Use StringUtils.isEmpty() for null-safe empty check
- Note: #2 and #3 already addressed in previous commit

* Revision 3: Use IdGenerator.getTimeOrderedEpoch() for UUID bounds

- Simplified InstantToUUIDMapper to use IdGenerator.getTimeOrderedEpoch() instead of convertOtelIdToUUIDv7
- Per UUIDv7 RFC, sub-millisecond 12 bits are optional with millisecond granularity
- Start/end interval semantics with ±1ms ensures correct BETWEEN query results
- This approach has been battle-tested for months without issues per reviewer recommendation
- Converted InstantToUUIDMapper to @singleton service for proper DI integration
- Updated TracesResource to inject InstantToUUIDMapper dependency
- Updated tests to properly mock IdGenerator dependency

* Fix tests

* [OPIK-2856] [BE] Split Get spans Tests

* Fix format

* Revision 2: Extract duplicated span creation logic into createSpanWithTimestamp helper method

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for spans

* Revision 3: Extract workspace setup duplication into setupTestWorkspace helper method and fix transformTestParams call

* [OPIK-2856] Refactor TracesResourceTest to use TraceResourceClient instead of direct URL_TEMPLATE calls

- Replace all direct client.target(URL_TEMPLATE) calls with TraceResourceClient methods
- Add callFeedbackScoresWithCookie method to TraceResourceClient for session token authentication
- Add callRetrieveThreadResponseWithCookie method to TraceResourceClient for session token authentication
- Fix feedback batch endpoint by using callFeedbackScores and callFeedbackScoresWithCookie
- Add null checks for query parameters to prevent NPE errors
- Fix API key vs session token usage in authentication tests
- Rename get__whenApiKeyIsPresent__thenReturnTraceThread to get__whenSessionTokenIsPresent__thenReturnTraceThread in SessionTokenCookie class
- Add mockGetWorkspaceIdByName() calls for proper workspace mocking
- Preserve original test assertions and behavior
- All tests properly refactored to use resource client methods instead of direct HTTP calls

* [OPIK-2856] Remove duplicate methods from TraceResourceClient

- Remove callGetTraces() - duplicate of callGetTracesWithQueryParams()
- Remove callSearchTraces() - duplicate of callSearchTracesStream()
- Reduced code duplication and maintenance burden

* Fix tests

* Revision 2: Address Copilot review comments - remove redundant wrapper method and add clarifying comment

* Revision 3: Extract duplicated path splitting logic into helper method addPathSegments()

* Revision 4: Make getWebTarget() private and add callGetTraceThreadsWithSorting() public method

* Revision 7: Move addPathSegments() and addQueryParameters() helper methods to BaseCommentResourceClient

* [OPIK-2856] [BE] Add UUIDv7 time-based filtering for trace threads

* Revision 2: Address GitHub Copilot PR review comments

- Extract conditional UUID generation into generateThreadModelId() method for better readability
- Rename minTraceTimestamp to earliestTraceTimestamp for clarity
- Add explanatory comment about UUIDv7 lexicographic ordering in compareTo()

* Fix

* Revision 3: Add UUID time filter to SELECT_TRACES_STATS query

* Revision 4: Fix generateUUIDForTimestamp to manually construct UUIDv7
thiagohora added a commit that referenced this pull request Nov 12, 2025
…trics (#3969)

* [NA] [BE] Upgrade MySQL container from Testcontainers

* Fix imports order

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for traces

- Add InstantToUUIDMapper to convert Instant timestamps to UUIDv7 bounds
- Add InstantParamConverter to parse ISO-8601 and epoch millisecond time parameters
- Update TracesResource to accept from_time and to_time parameters on /traces and /traces/stats endpoints
- Update TraceDAO to apply UUID-based time filtering using BETWEEN clause on id column
- Update TraceSearchCriteria to include uuidFromTime and uuidToTime fields
- Add comprehensive integration tests for time filtering with boundary conditions
- All tests passing: 10/10 time filtering tests + validation tests

* [OPIK-2856] Address PR review comments: improve exception handling and type safety

- Fix InstantParamConverter to catch specific DateTimeParseException instead of generic Exception
- Add debug logging when falling back to epoch milliseconds parsing
- Refactor anonymous ParamConverter class to named InstantConverter inner class for clarity
- Suppress unchecked cast with @SuppressWarnings annotation
- Fix MySQLContainerUtils return type to use MySQLContainer<?> for type safety

* [OPIK-2856] Fix InstantToUUIDMapperTest to match implementation

- Update tests to reflect that toUpperBound uses next millisecond (+1ms) for inclusive BETWEEN queries
- Remove outdated assertions expecting same timestamp in both bounds
- Verify upper bound is lexicographically greater than lower bound
- All 13 tests now passing

* Remove setup duplicated code

* Revision 2: Address PR review comments - LOW priority fixes

- #7: Add INSTANCE singleton pattern for InstantConverter
- #8: Use StringUtils.isEmpty() for null-safe empty check
- Note: #2 and #3 already addressed in previous commit

* Revision 3: Use IdGenerator.getTimeOrderedEpoch() for UUID bounds

- Simplified InstantToUUIDMapper to use IdGenerator.getTimeOrderedEpoch() instead of convertOtelIdToUUIDv7
- Per UUIDv7 RFC, sub-millisecond 12 bits are optional with millisecond granularity
- Start/end interval semantics with ±1ms ensures correct BETWEEN query results
- This approach has been battle-tested for months without issues per reviewer recommendation
- Converted InstantToUUIDMapper to @singleton service for proper DI integration
- Updated TracesResource to inject InstantToUUIDMapper dependency
- Updated tests to properly mock IdGenerator dependency

* Fix tests

* [OPIK-2856] [BE] Split Get spans Tests

* Fix format

* Revision 2: Extract duplicated span creation logic into createSpanWithTimestamp helper method

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for spans

* Revision 3: Extract workspace setup duplication into setupTestWorkspace helper method and fix transformTestParams call

* [OPIK-2856] Refactor TracesResourceTest to use TraceResourceClient instead of direct URL_TEMPLATE calls

- Replace all direct client.target(URL_TEMPLATE) calls with TraceResourceClient methods
- Add callFeedbackScoresWithCookie method to TraceResourceClient for session token authentication
- Add callRetrieveThreadResponseWithCookie method to TraceResourceClient for session token authentication
- Fix feedback batch endpoint by using callFeedbackScores and callFeedbackScoresWithCookie
- Add null checks for query parameters to prevent NPE errors
- Fix API key vs session token usage in authentication tests
- Rename get__whenApiKeyIsPresent__thenReturnTraceThread to get__whenSessionTokenIsPresent__thenReturnTraceThread in SessionTokenCookie class
- Add mockGetWorkspaceIdByName() calls for proper workspace mocking
- Preserve original test assertions and behavior
- All tests properly refactored to use resource client methods instead of direct HTTP calls

* [OPIK-2856] Remove duplicate methods from TraceResourceClient

- Remove callGetTraces() - duplicate of callGetTracesWithQueryParams()
- Remove callSearchTraces() - duplicate of callSearchTracesStream()
- Reduced code duplication and maintenance burden

* Fix tests

* Revision 2: Address Copilot review comments - remove redundant wrapper method and add clarifying comment

* Revision 3: Extract duplicated path splitting logic into helper method addPathSegments()

* Revision 4: Make getWebTarget() private and add callGetTraceThreadsWithSorting() public method

* Revision 7: Move addPathSegments() and addQueryParameters() helper methods to BaseCommentResourceClient

* [OPIK-2856] [BE] Add UUIDv7 time-based filtering for trace threads

* Revision 2: Address GitHub Copilot PR review comments

- Extract conditional UUID generation into generateThreadModelId() method for better readability
- Rename minTraceTimestamp to earliestTraceTimestamp for clarity
- Add explanatory comment about UUIDv7 lexicographic ordering in compareTo()

* Fix

* Revision 3: Add UUID time filter to SELECT_TRACES_STATS query

* Revision 4: Fix generateUUIDForTimestamp to manually construct UUIDv7

* [OPIK-2856] [BE] Implement UUIDv7-based time filtering for project metrics

- Add uuidFromTime and uuidToTime fields to ProjectMetricRequest
- Update ProjectMetricsService to enrich requests with UUID bounds using InstantToUUIDMapper
- Refactor ProjectMetricsDAO SQL queries to use UUID-based filtering (id BETWEEN uuid_from_time AND uuid_to_time)
- Extract timestamps from UUIDs using UUIDv7ToDateTime for bucketing and WITH FILL clauses
- Update TraceService to generate UUIDs based on trace startTime when ID is not provided
- Fix ProjectMetricsResourceTest to generate UUIDs with correct timestamps using TimeBasedEpochGenerator
- Remove explicit openTraceThread calls in tests to allow traces to create thread metadata with correct timestamps

All 206 ProjectMetricsResourceTest tests now passing (1 skipped).

* [OPIK-2856] Fix flaky MultiValueFeedbackScoresE2ETest by ensuring UUID bounds are min/max for timestamp

* [OPIK-2856] Update InstantToUUIDMapper tests to match new min/max UUID implementation

* [OPIK-2856] Address Copilot PR review comments: clarify 62-bit constant and update validateProject comment

* [OPIK-2856] [BE] Extract UUID utility for test reuse

- Create UUIDTestUtils with generateUUIDForTimestamp method
- Replace local implementations in ProjectMetricsResourceTest
- Replace local implementations in FindSpansResourceTest
- Remove duplicate method definitions and unused imports
- Centralize UUID generation logic for time-based testing

Tests verified: ✅ ProjectMetricsResourceTest (206 tests passed, 1 skipped)

* Revert id changes
thiagohora added a commit that referenced this pull request Nov 12, 2025
…bs (#3977)

* [NA] [BE] Upgrade MySQL container from Testcontainers

* Fix imports order

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for traces

- Add InstantToUUIDMapper to convert Instant timestamps to UUIDv7 bounds
- Add InstantParamConverter to parse ISO-8601 and epoch millisecond time parameters
- Update TracesResource to accept from_time and to_time parameters on /traces and /traces/stats endpoints
- Update TraceDAO to apply UUID-based time filtering using BETWEEN clause on id column
- Update TraceSearchCriteria to include uuidFromTime and uuidToTime fields
- Add comprehensive integration tests for time filtering with boundary conditions
- All tests passing: 10/10 time filtering tests + validation tests

* [OPIK-2856] Address PR review comments: improve exception handling and type safety

- Fix InstantParamConverter to catch specific DateTimeParseException instead of generic Exception
- Add debug logging when falling back to epoch milliseconds parsing
- Refactor anonymous ParamConverter class to named InstantConverter inner class for clarity
- Suppress unchecked cast with @SuppressWarnings annotation
- Fix MySQLContainerUtils return type to use MySQLContainer<?> for type safety

* [OPIK-2856] Fix InstantToUUIDMapperTest to match implementation

- Update tests to reflect that toUpperBound uses next millisecond (+1ms) for inclusive BETWEEN queries
- Remove outdated assertions expecting same timestamp in both bounds
- Verify upper bound is lexicographically greater than lower bound
- All 13 tests now passing

* Remove setup duplicated code

* Revision 2: Address PR review comments - LOW priority fixes

- #7: Add INSTANCE singleton pattern for InstantConverter
- #8: Use StringUtils.isEmpty() for null-safe empty check
- Note: #2 and #3 already addressed in previous commit

* Revision 3: Use IdGenerator.getTimeOrderedEpoch() for UUID bounds

- Simplified InstantToUUIDMapper to use IdGenerator.getTimeOrderedEpoch() instead of convertOtelIdToUUIDv7
- Per UUIDv7 RFC, sub-millisecond 12 bits are optional with millisecond granularity
- Start/end interval semantics with ±1ms ensures correct BETWEEN query results
- This approach has been battle-tested for months without issues per reviewer recommendation
- Converted InstantToUUIDMapper to @singleton service for proper DI integration
- Updated TracesResource to inject InstantToUUIDMapper dependency
- Updated tests to properly mock IdGenerator dependency

* Fix tests

* [OPIK-2856] [BE] Split Get spans Tests

* Fix format

* Revision 2: Extract duplicated span creation logic into createSpanWithTimestamp helper method

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for spans

* Revision 3: Extract workspace setup duplication into setupTestWorkspace helper method and fix transformTestParams call

* [OPIK-2856] Refactor TracesResourceTest to use TraceResourceClient instead of direct URL_TEMPLATE calls

- Replace all direct client.target(URL_TEMPLATE) calls with TraceResourceClient methods
- Add callFeedbackScoresWithCookie method to TraceResourceClient for session token authentication
- Add callRetrieveThreadResponseWithCookie method to TraceResourceClient for session token authentication
- Fix feedback batch endpoint by using callFeedbackScores and callFeedbackScoresWithCookie
- Add null checks for query parameters to prevent NPE errors
- Fix API key vs session token usage in authentication tests
- Rename get__whenApiKeyIsPresent__thenReturnTraceThread to get__whenSessionTokenIsPresent__thenReturnTraceThread in SessionTokenCookie class
- Add mockGetWorkspaceIdByName() calls for proper workspace mocking
- Preserve original test assertions and behavior
- All tests properly refactored to use resource client methods instead of direct HTTP calls

* [OPIK-2856] Remove duplicate methods from TraceResourceClient

- Remove callGetTraces() - duplicate of callGetTracesWithQueryParams()
- Remove callSearchTraces() - duplicate of callSearchTracesStream()
- Reduced code duplication and maintenance burden

* Fix tests

* Revision 2: Address Copilot review comments - remove redundant wrapper method and add clarifying comment

* Revision 3: Extract duplicated path splitting logic into helper method addPathSegments()

* Revision 4: Make getWebTarget() private and add callGetTraceThreadsWithSorting() public method

* Revision 7: Move addPathSegments() and addQueryParameters() helper methods to BaseCommentResourceClient

* [OPIK-2856] [BE] Add UUIDv7 time-based filtering for trace threads

* Revision 2: Address GitHub Copilot PR review comments

- Extract conditional UUID generation into generateThreadModelId() method for better readability
- Rename minTraceTimestamp to earliestTraceTimestamp for clarity
- Add explanatory comment about UUIDv7 lexicographic ordering in compareTo()

* Fix

* Revision 3: Add UUID time filter to SELECT_TRACES_STATS query

* Revision 4: Fix generateUUIDForTimestamp to manually construct UUIDv7

* [OPIK-2856] [BE] Implement UUIDv7-based time filtering for project metrics

- Add uuidFromTime and uuidToTime fields to ProjectMetricRequest
- Update ProjectMetricsService to enrich requests with UUID bounds using InstantToUUIDMapper
- Refactor ProjectMetricsDAO SQL queries to use UUID-based filtering (id BETWEEN uuid_from_time AND uuid_to_time)
- Extract timestamps from UUIDs using UUIDv7ToDateTime for bucketing and WITH FILL clauses
- Update TraceService to generate UUIDs based on trace startTime when ID is not provided
- Fix ProjectMetricsResourceTest to generate UUIDs with correct timestamps using TimeBasedEpochGenerator
- Remove explicit openTraceThread calls in tests to allow traces to create thread metadata with correct timestamps

All 206 ProjectMetricsResourceTest tests now passing (1 skipped).

* [OPIK-2856] Fix flaky MultiValueFeedbackScoresE2ETest by ensuring UUID bounds are min/max for timestamp

* [OPIK-2856] Update InstantToUUIDMapper tests to match new min/max UUID implementation

* [OPIK-2856] Address Copilot PR review comments: clarify 62-bit constant and update validateProject comment

* [OPIK-2856] [FE] Add datetime picker to traces, spans, and threads tabs

* Revision 2: Synchronize date range across all tabs using shared 'range' key

* Revision 3: Add refetchOnMount to ensure data refreshes when switching tabs

* Revision 4: Fix TypeScript error - change refetchOnMount from 'stale' to 'always'

* Fix date range

* Update SpanService.java

* Update TraceService.java

* Update ProjectMetricsResourceTest.java
awkoy pushed a commit that referenced this pull request Nov 12, 2025
)

* [NA] [BE] Upgrade MySQL container from Testcontainers

* Fix imports order

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for traces

- Add InstantToUUIDMapper to convert Instant timestamps to UUIDv7 bounds
- Add InstantParamConverter to parse ISO-8601 and epoch millisecond time parameters
- Update TracesResource to accept from_time and to_time parameters on /traces and /traces/stats endpoints
- Update TraceDAO to apply UUID-based time filtering using BETWEEN clause on id column
- Update TraceSearchCriteria to include uuidFromTime and uuidToTime fields
- Add comprehensive integration tests for time filtering with boundary conditions
- All tests passing: 10/10 time filtering tests + validation tests

* [OPIK-2856] Address PR review comments: improve exception handling and type safety

- Fix InstantParamConverter to catch specific DateTimeParseException instead of generic Exception
- Add debug logging when falling back to epoch milliseconds parsing
- Refactor anonymous ParamConverter class to named InstantConverter inner class for clarity
- Suppress unchecked cast with @SuppressWarnings annotation
- Fix MySQLContainerUtils return type to use MySQLContainer<?> for type safety

* [OPIK-2856] Fix InstantToUUIDMapperTest to match implementation

- Update tests to reflect that toUpperBound uses next millisecond (+1ms) for inclusive BETWEEN queries
- Remove outdated assertions expecting same timestamp in both bounds
- Verify upper bound is lexicographically greater than lower bound
- All 13 tests now passing

* Remove setup duplicated code

* Revision 2: Address PR review comments - LOW priority fixes

- #7: Add INSTANCE singleton pattern for InstantConverter
- #8: Use StringUtils.isEmpty() for null-safe empty check
- Note: #2 and #3 already addressed in previous commit

* Revision 3: Use IdGenerator.getTimeOrderedEpoch() for UUID bounds

- Simplified InstantToUUIDMapper to use IdGenerator.getTimeOrderedEpoch() instead of convertOtelIdToUUIDv7
- Per UUIDv7 RFC, sub-millisecond 12 bits are optional with millisecond granularity
- Start/end interval semantics with ±1ms ensures correct BETWEEN query results
- This approach has been battle-tested for months without issues per reviewer recommendation
- Converted InstantToUUIDMapper to @singleton service for proper DI integration
- Updated TracesResource to inject InstantToUUIDMapper dependency
- Updated tests to properly mock IdGenerator dependency

* Fix tests
awkoy pushed a commit that referenced this pull request Nov 12, 2025
* [NA] [BE] Upgrade MySQL container from Testcontainers

* Fix imports order

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for traces

- Add InstantToUUIDMapper to convert Instant timestamps to UUIDv7 bounds
- Add InstantParamConverter to parse ISO-8601 and epoch millisecond time parameters
- Update TracesResource to accept from_time and to_time parameters on /traces and /traces/stats endpoints
- Update TraceDAO to apply UUID-based time filtering using BETWEEN clause on id column
- Update TraceSearchCriteria to include uuidFromTime and uuidToTime fields
- Add comprehensive integration tests for time filtering with boundary conditions
- All tests passing: 10/10 time filtering tests + validation tests

* [OPIK-2856] Address PR review comments: improve exception handling and type safety

- Fix InstantParamConverter to catch specific DateTimeParseException instead of generic Exception
- Add debug logging when falling back to epoch milliseconds parsing
- Refactor anonymous ParamConverter class to named InstantConverter inner class for clarity
- Suppress unchecked cast with @SuppressWarnings annotation
- Fix MySQLContainerUtils return type to use MySQLContainer<?> for type safety

* [OPIK-2856] Fix InstantToUUIDMapperTest to match implementation

- Update tests to reflect that toUpperBound uses next millisecond (+1ms) for inclusive BETWEEN queries
- Remove outdated assertions expecting same timestamp in both bounds
- Verify upper bound is lexicographically greater than lower bound
- All 13 tests now passing

* Remove setup duplicated code

* Revision 2: Address PR review comments - LOW priority fixes

- #7: Add INSTANCE singleton pattern for InstantConverter
- #8: Use StringUtils.isEmpty() for null-safe empty check
- Note: #2 and #3 already addressed in previous commit

* Revision 3: Use IdGenerator.getTimeOrderedEpoch() for UUID bounds

- Simplified InstantToUUIDMapper to use IdGenerator.getTimeOrderedEpoch() instead of convertOtelIdToUUIDv7
- Per UUIDv7 RFC, sub-millisecond 12 bits are optional with millisecond granularity
- Start/end interval semantics with ±1ms ensures correct BETWEEN query results
- This approach has been battle-tested for months without issues per reviewer recommendation
- Converted InstantToUUIDMapper to @singleton service for proper DI integration
- Updated TracesResource to inject InstantToUUIDMapper dependency
- Updated tests to properly mock IdGenerator dependency

* Fix tests

* [OPIK-2856] [BE] Split Get spans Tests

* Fix format
awkoy pushed a commit that referenced this pull request Nov 12, 2025
* [NA] [BE] Upgrade MySQL container from Testcontainers

* Fix imports order

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for traces

- Add InstantToUUIDMapper to convert Instant timestamps to UUIDv7 bounds
- Add InstantParamConverter to parse ISO-8601 and epoch millisecond time parameters
- Update TracesResource to accept from_time and to_time parameters on /traces and /traces/stats endpoints
- Update TraceDAO to apply UUID-based time filtering using BETWEEN clause on id column
- Update TraceSearchCriteria to include uuidFromTime and uuidToTime fields
- Add comprehensive integration tests for time filtering with boundary conditions
- All tests passing: 10/10 time filtering tests + validation tests

* [OPIK-2856] Address PR review comments: improve exception handling and type safety

- Fix InstantParamConverter to catch specific DateTimeParseException instead of generic Exception
- Add debug logging when falling back to epoch milliseconds parsing
- Refactor anonymous ParamConverter class to named InstantConverter inner class for clarity
- Suppress unchecked cast with @SuppressWarnings annotation
- Fix MySQLContainerUtils return type to use MySQLContainer<?> for type safety

* [OPIK-2856] Fix InstantToUUIDMapperTest to match implementation

- Update tests to reflect that toUpperBound uses next millisecond (+1ms) for inclusive BETWEEN queries
- Remove outdated assertions expecting same timestamp in both bounds
- Verify upper bound is lexicographically greater than lower bound
- All 13 tests now passing

* Remove setup duplicated code

* Revision 2: Address PR review comments - LOW priority fixes

- #7: Add INSTANCE singleton pattern for InstantConverter
- #8: Use StringUtils.isEmpty() for null-safe empty check
- Note: #2 and #3 already addressed in previous commit

* Revision 3: Use IdGenerator.getTimeOrderedEpoch() for UUID bounds

- Simplified InstantToUUIDMapper to use IdGenerator.getTimeOrderedEpoch() instead of convertOtelIdToUUIDv7
- Per UUIDv7 RFC, sub-millisecond 12 bits are optional with millisecond granularity
- Start/end interval semantics with ±1ms ensures correct BETWEEN query results
- This approach has been battle-tested for months without issues per reviewer recommendation
- Converted InstantToUUIDMapper to @singleton service for proper DI integration
- Updated TracesResource to inject InstantToUUIDMapper dependency
- Updated tests to properly mock IdGenerator dependency

* Fix tests

* [OPIK-2856] [BE] Split Get spans Tests

* Fix format

* Revision 2: Extract duplicated span creation logic into createSpanWithTimestamp helper method

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for spans

* Revision 3: Extract workspace setup duplication into setupTestWorkspace helper method and fix transformTestParams call
awkoy pushed a commit that referenced this pull request Nov 12, 2025
…d of direct URL_TEMPLATE calls (#3947)

* [NA] [BE] Upgrade MySQL container from Testcontainers

* Fix imports order

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for traces

- Add InstantToUUIDMapper to convert Instant timestamps to UUIDv7 bounds
- Add InstantParamConverter to parse ISO-8601 and epoch millisecond time parameters
- Update TracesResource to accept from_time and to_time parameters on /traces and /traces/stats endpoints
- Update TraceDAO to apply UUID-based time filtering using BETWEEN clause on id column
- Update TraceSearchCriteria to include uuidFromTime and uuidToTime fields
- Add comprehensive integration tests for time filtering with boundary conditions
- All tests passing: 10/10 time filtering tests + validation tests

* [OPIK-2856] Address PR review comments: improve exception handling and type safety

- Fix InstantParamConverter to catch specific DateTimeParseException instead of generic Exception
- Add debug logging when falling back to epoch milliseconds parsing
- Refactor anonymous ParamConverter class to named InstantConverter inner class for clarity
- Suppress unchecked cast with @SuppressWarnings annotation
- Fix MySQLContainerUtils return type to use MySQLContainer<?> for type safety

* [OPIK-2856] Fix InstantToUUIDMapperTest to match implementation

- Update tests to reflect that toUpperBound uses next millisecond (+1ms) for inclusive BETWEEN queries
- Remove outdated assertions expecting same timestamp in both bounds
- Verify upper bound is lexicographically greater than lower bound
- All 13 tests now passing

* Remove setup duplicated code

* Revision 2: Address PR review comments - LOW priority fixes

- #7: Add INSTANCE singleton pattern for InstantConverter
- #8: Use StringUtils.isEmpty() for null-safe empty check
- Note: #2 and #3 already addressed in previous commit

* Revision 3: Use IdGenerator.getTimeOrderedEpoch() for UUID bounds

- Simplified InstantToUUIDMapper to use IdGenerator.getTimeOrderedEpoch() instead of convertOtelIdToUUIDv7
- Per UUIDv7 RFC, sub-millisecond 12 bits are optional with millisecond granularity
- Start/end interval semantics with ±1ms ensures correct BETWEEN query results
- This approach has been battle-tested for months without issues per reviewer recommendation
- Converted InstantToUUIDMapper to @singleton service for proper DI integration
- Updated TracesResource to inject InstantToUUIDMapper dependency
- Updated tests to properly mock IdGenerator dependency

* Fix tests

* [OPIK-2856] [BE] Split Get spans Tests

* Fix format

* Revision 2: Extract duplicated span creation logic into createSpanWithTimestamp helper method

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for spans

* Revision 3: Extract workspace setup duplication into setupTestWorkspace helper method and fix transformTestParams call

* [OPIK-2856] Refactor TracesResourceTest to use TraceResourceClient instead of direct URL_TEMPLATE calls

- Replace all direct client.target(URL_TEMPLATE) calls with TraceResourceClient methods
- Add callFeedbackScoresWithCookie method to TraceResourceClient for session token authentication
- Add callRetrieveThreadResponseWithCookie method to TraceResourceClient for session token authentication
- Fix feedback batch endpoint by using callFeedbackScores and callFeedbackScoresWithCookie
- Add null checks for query parameters to prevent NPE errors
- Fix API key vs session token usage in authentication tests
- Rename get__whenApiKeyIsPresent__thenReturnTraceThread to get__whenSessionTokenIsPresent__thenReturnTraceThread in SessionTokenCookie class
- Add mockGetWorkspaceIdByName() calls for proper workspace mocking
- Preserve original test assertions and behavior
- All tests properly refactored to use resource client methods instead of direct HTTP calls

* [OPIK-2856] Remove duplicate methods from TraceResourceClient

- Remove callGetTraces() - duplicate of callGetTracesWithQueryParams()
- Remove callSearchTraces() - duplicate of callSearchTracesStream()
- Reduced code duplication and maintenance burden

* Fix tests

* Revision 2: Address Copilot review comments - remove redundant wrapper method and add clarifying comment

* Revision 3: Extract duplicated path splitting logic into helper method addPathSegments()

* Revision 4: Make getWebTarget() private and add callGetTraceThreadsWithSorting() public method

* Revision 7: Move addPathSegments() and addQueryParameters() helper methods to BaseCommentResourceClient
awkoy pushed a commit that referenced this pull request Nov 12, 2025
…3953)

* [NA] [BE] Upgrade MySQL container from Testcontainers

* Fix imports order

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for traces

- Add InstantToUUIDMapper to convert Instant timestamps to UUIDv7 bounds
- Add InstantParamConverter to parse ISO-8601 and epoch millisecond time parameters
- Update TracesResource to accept from_time and to_time parameters on /traces and /traces/stats endpoints
- Update TraceDAO to apply UUID-based time filtering using BETWEEN clause on id column
- Update TraceSearchCriteria to include uuidFromTime and uuidToTime fields
- Add comprehensive integration tests for time filtering with boundary conditions
- All tests passing: 10/10 time filtering tests + validation tests

* [OPIK-2856] Address PR review comments: improve exception handling and type safety

- Fix InstantParamConverter to catch specific DateTimeParseException instead of generic Exception
- Add debug logging when falling back to epoch milliseconds parsing
- Refactor anonymous ParamConverter class to named InstantConverter inner class for clarity
- Suppress unchecked cast with @SuppressWarnings annotation
- Fix MySQLContainerUtils return type to use MySQLContainer<?> for type safety

* [OPIK-2856] Fix InstantToUUIDMapperTest to match implementation

- Update tests to reflect that toUpperBound uses next millisecond (+1ms) for inclusive BETWEEN queries
- Remove outdated assertions expecting same timestamp in both bounds
- Verify upper bound is lexicographically greater than lower bound
- All 13 tests now passing

* Remove setup duplicated code

* Revision 2: Address PR review comments - LOW priority fixes

- #7: Add INSTANCE singleton pattern for InstantConverter
- #8: Use StringUtils.isEmpty() for null-safe empty check
- Note: #2 and #3 already addressed in previous commit

* Revision 3: Use IdGenerator.getTimeOrderedEpoch() for UUID bounds

- Simplified InstantToUUIDMapper to use IdGenerator.getTimeOrderedEpoch() instead of convertOtelIdToUUIDv7
- Per UUIDv7 RFC, sub-millisecond 12 bits are optional with millisecond granularity
- Start/end interval semantics with ±1ms ensures correct BETWEEN query results
- This approach has been battle-tested for months without issues per reviewer recommendation
- Converted InstantToUUIDMapper to @singleton service for proper DI integration
- Updated TracesResource to inject InstantToUUIDMapper dependency
- Updated tests to properly mock IdGenerator dependency

* Fix tests

* [OPIK-2856] [BE] Split Get spans Tests

* Fix format

* Revision 2: Extract duplicated span creation logic into createSpanWithTimestamp helper method

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for spans

* Revision 3: Extract workspace setup duplication into setupTestWorkspace helper method and fix transformTestParams call

* [OPIK-2856] Refactor TracesResourceTest to use TraceResourceClient instead of direct URL_TEMPLATE calls

- Replace all direct client.target(URL_TEMPLATE) calls with TraceResourceClient methods
- Add callFeedbackScoresWithCookie method to TraceResourceClient for session token authentication
- Add callRetrieveThreadResponseWithCookie method to TraceResourceClient for session token authentication
- Fix feedback batch endpoint by using callFeedbackScores and callFeedbackScoresWithCookie
- Add null checks for query parameters to prevent NPE errors
- Fix API key vs session token usage in authentication tests
- Rename get__whenApiKeyIsPresent__thenReturnTraceThread to get__whenSessionTokenIsPresent__thenReturnTraceThread in SessionTokenCookie class
- Add mockGetWorkspaceIdByName() calls for proper workspace mocking
- Preserve original test assertions and behavior
- All tests properly refactored to use resource client methods instead of direct HTTP calls

* [OPIK-2856] Remove duplicate methods from TraceResourceClient

- Remove callGetTraces() - duplicate of callGetTracesWithQueryParams()
- Remove callSearchTraces() - duplicate of callSearchTracesStream()
- Reduced code duplication and maintenance burden

* Fix tests

* Revision 2: Address Copilot review comments - remove redundant wrapper method and add clarifying comment

* Revision 3: Extract duplicated path splitting logic into helper method addPathSegments()

* Revision 4: Make getWebTarget() private and add callGetTraceThreadsWithSorting() public method

* Revision 7: Move addPathSegments() and addQueryParameters() helper methods to BaseCommentResourceClient

* [OPIK-2856] [BE] Add UUIDv7 time-based filtering for trace threads

* Revision 2: Address GitHub Copilot PR review comments

- Extract conditional UUID generation into generateThreadModelId() method for better readability
- Rename minTraceTimestamp to earliestTraceTimestamp for clarity
- Add explanatory comment about UUIDv7 lexicographic ordering in compareTo()

* Fix

* Revision 3: Add UUID time filter to SELECT_TRACES_STATS query

* Revision 4: Fix generateUUIDForTimestamp to manually construct UUIDv7
thiagohora added a commit that referenced this pull request Nov 12, 2025
* [NA] [BE] Upgrade MySQL container from Testcontainers

* Fix imports order

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for traces

- Add InstantToUUIDMapper to convert Instant timestamps to UUIDv7 bounds
- Add InstantParamConverter to parse ISO-8601 and epoch millisecond time parameters
- Update TracesResource to accept from_time and to_time parameters on /traces and /traces/stats endpoints
- Update TraceDAO to apply UUID-based time filtering using BETWEEN clause on id column
- Update TraceSearchCriteria to include uuidFromTime and uuidToTime fields
- Add comprehensive integration tests for time filtering with boundary conditions
- All tests passing: 10/10 time filtering tests + validation tests

* [OPIK-2856] Address PR review comments: improve exception handling and type safety

- Fix InstantParamConverter to catch specific DateTimeParseException instead of generic Exception
- Add debug logging when falling back to epoch milliseconds parsing
- Refactor anonymous ParamConverter class to named InstantConverter inner class for clarity
- Suppress unchecked cast with @SuppressWarnings annotation
- Fix MySQLContainerUtils return type to use MySQLContainer<?> for type safety

* [OPIK-2856] Fix InstantToUUIDMapperTest to match implementation

- Update tests to reflect that toUpperBound uses next millisecond (+1ms) for inclusive BETWEEN queries
- Remove outdated assertions expecting same timestamp in both bounds
- Verify upper bound is lexicographically greater than lower bound
- All 13 tests now passing

* Remove setup duplicated code

* Revision 2: Address PR review comments - LOW priority fixes

- #7: Add INSTANCE singleton pattern for InstantConverter
- #8: Use StringUtils.isEmpty() for null-safe empty check
- Note: #2 and #3 already addressed in previous commit

* Revision 3: Use IdGenerator.getTimeOrderedEpoch() for UUID bounds

- Simplified InstantToUUIDMapper to use IdGenerator.getTimeOrderedEpoch() instead of convertOtelIdToUUIDv7
- Per UUIDv7 RFC, sub-millisecond 12 bits are optional with millisecond granularity
- Start/end interval semantics with ±1ms ensures correct BETWEEN query results
- This approach has been battle-tested for months without issues per reviewer recommendation
- Converted InstantToUUIDMapper to @singleton service for proper DI integration
- Updated TracesResource to inject InstantToUUIDMapper dependency
- Updated tests to properly mock IdGenerator dependency

* Fix tests

* [OPIK-2856] [BE] Split Get spans Tests

* Fix format

* Revision 2: Extract duplicated span creation logic into createSpanWithTimestamp helper method

* [OPIK-2856] [BE] Implement UUIDv7 time-based filtering for spans

* Revision 3: Extract workspace setup duplication into setupTestWorkspace helper method and fix transformTestParams call

* [OPIK-2856] Refactor TracesResourceTest to use TraceResourceClient instead of direct URL_TEMPLATE calls

- Replace all direct client.target(URL_TEMPLATE) calls with TraceResourceClient methods
- Add callFeedbackScoresWithCookie method to TraceResourceClient for session token authentication
- Add callRetrieveThreadResponseWithCookie method to TraceResourceClient for session token authentication
- Fix feedback batch endpoint by using callFeedbackScores and callFeedbackScoresWithCookie
- Add null checks for query parameters to prevent NPE errors
- Fix API key vs session token usage in authentication tests
- Rename get__whenApiKeyIsPresent__thenReturnTraceThread to get__whenSessionTokenIsPresent__thenReturnTraceThread in SessionTokenCookie class
- Add mockGetWorkspaceIdByName() calls for proper workspace mocking
- Preserve original test assertions and behavior
- All tests properly refactored to use resource client methods instead of direct HTTP calls

* [OPIK-2856] Remove duplicate methods from TraceResourceClient

- Remove callGetTraces() - duplicate of callGetTracesWithQueryParams()
- Remove callSearchTraces() - duplicate of callSearchTracesStream()
- Reduced code duplication and maintenance burden

* Fix tests

* Revision 2: Address Copilot review comments - remove redundant wrapper method and add clarifying comment

* Revision 3: Extract duplicated path splitting logic into helper method addPathSegments()

* Revision 4: Make getWebTarget() private and add callGetTraceThreadsWithSorting() public method

* Revision 7: Move addPathSegments() and addQueryParameters() helper methods to BaseCommentResourceClient

* [OPIK-2856] [BE] Add UUIDv7 time-based filtering for trace threads

* Revision 2: Address GitHub Copilot PR review comments

- Extract conditional UUID generation into generateThreadModelId() method for better readability
- Rename minTraceTimestamp to earliestTraceTimestamp for clarity
- Add explanatory comment about UUIDv7 lexicographic ordering in compareTo()

* Fix

* Revision 3: Add UUID time filter to SELECT_TRACES_STATS query

* Revision 4: Fix generateUUIDForTimestamp to manually construct UUIDv7

* [OPIK-2856] [BE] Implement UUIDv7-based time filtering for project metrics

- Add uuidFromTime and uuidToTime fields to ProjectMetricRequest
- Update ProjectMetricsService to enrich requests with UUID bounds using InstantToUUIDMapper
- Refactor ProjectMetricsDAO SQL queries to use UUID-based filtering (id BETWEEN uuid_from_time AND uuid_to_time)
- Extract timestamps from UUIDs using UUIDv7ToDateTime for bucketing and WITH FILL clauses
- Update TraceService to generate UUIDs based on trace startTime when ID is not provided
- Fix ProjectMetricsResourceTest to generate UUIDs with correct timestamps using TimeBasedEpochGenerator
- Remove explicit openTraceThread calls in tests to allow traces to create thread metadata with correct timestamps

All 206 ProjectMetricsResourceTest tests now passing (1 skipped).

* [OPIK-2856] Fix flaky MultiValueFeedbackScoresE2ETest by ensuring UUID bounds are min/max for timestamp

* [OPIK-2856] Update InstantToUUIDMapper tests to match new min/max UUID implementation

* [OPIK-2856] Address Copilot PR review comments: clarify 62-bit constant and update validateProject comment

* [OPIK-2856] [BE] Extract UUID utility for test reuse

- Create UUIDTestUtils with generateUUIDForTimestamp method
- Replace local implementations in ProjectMetricsResourceTest
- Replace local implementations in FindSpansResourceTest
- Remove duplicate method definitions and unused imports
- Centralize UUID generation logic for time-based testing

Tests verified: ✅ ProjectMetricsResourceTest (206 tests passed, 1 skipped)

* Revert id changes

* [OPIK-2856] [BE] Use batch calls to reduce test duration
JetoPistola added a commit that referenced this pull request Dec 1, 2025
Python SDK improvements:
- Import module instead of name for ExperimentScore (comment #2)
- Allow ExperimentScoreFunction to return single or List of ScoreResults (comment #3)
- Move experiment score verification to verify_experiment utility (comment #4)

Backend code quality:
- Simplify TypeReference diamond operator in ExperimentScore.java (comment #5)
- Remove overloaded constructor in FeedbackScoreNames.ScoreName (comment #6)
- Reuse ScoreName instead of ScoreNameWithType in DAO (comment #7)
- Add TODO for full primary key in ORDER BY (comment #8)
- Revert flakiness fix in TemplateUtilsTest.java (comment #9)
JetoPistola added a commit that referenced this pull request Dec 2, 2025
…nctions (#3989)

* Hide experiment_scores columns in the single experiment table

* Add SDK support for experiment_scores

* Add SDK support for experiment_scores

* Add BE functionality

* Typescript autogenerated code

* Documentation and FE update

* Address PR comments

* Address PR comments

* Fix PR comments

* Address PR comments

* Fix merge conflicts

* Fix tests

* Fix failing tests

* Fix failing tests

* Fix UI colors and column names

* Refactor: Extract common score averaging logic to eliminate duplication

* Harmonize experiment scores sorting to use map access from CTE

- Add experiment_scores_agg LEFT JOIN to non-grouped queries
- Simplify SortingQueryBuilder to use coalesce(map[key]) instead of complex JSON extraction
- Remove special case handling for experiment_scores in null direction logic
- Addresses PR review comments about query harmonization

* Remove early return for empty test results in experiment scores

- Allow experiment score functions to handle empty test results
- Some functions may want to return baseline/default scores with no data
- Addresses PR review comment about preventing score function execution

* Add E2E test for experiment scores functionality

- Test verifies experiment scoring functions work end-to-end
- Validates experiment scores appear in evaluation result
- Validates experiment scores are retrievable via SDK API
- Uses compute_max_score function to test score aggregation
- Addresses PR review comment about E2E test coverage

* Enhance experiment score computation to handle empty test results gracefully

- Update condition to return empty list if either scoring functions or test results are absent
- Ensures robustness in score computation logic

* Add Python SDK E2E test for experiment scores

- Tests experiment_scoring_functions parameter in evaluate()
- Verifies experiment scores are computed and returned in result
- Validates scores are persisted to backend API
- Tests aggregate metrics (max, min, avg) computation
- Addresses PR review comment about SDK test coverage

* Revert "Add E2E test for experiment scores functionality"

This reverts commit 50f9f8d.

* Apply DRY principle to score type mapping in ExperimentFeedbackScoresTab

- Extract addScoresToMap helper function to avoid duplication
- Works for both feedback_scores and experiment_scores
- Reduces code duplication and improves maintainability
- Fix parameter ordering (required before optional)

* [FE] Apply DRY principle to feedback/experiment scores handling

- useExperimentsTableConfig: Extract getScoreByName helper, eliminate duplicate accessorFn logic
- useCompareExperimentsChartsData: Extract createScoresMap helper for both score types
- CompareExperimentsDetails: Extract markScores helper to avoid duplicate map calls
- ExperimentsPage: Extract createScoresMap and getScoreNames helpers
- EvaluationSection: Use shared transformExperimentScores utility
- experimentScoreUtils: Refactor with formatScores helper to eliminate duplication

All changes maintain type safety and pass linting/typecheck

* Revision 7: Add missing experiment_scores_agg CTE to FIND query

* Revision 8: Fix experiment_scores sorting to use correct CTE alias 'es'

* Revision 9: Address all 9 PR review comments

Python SDK improvements:
- Import module instead of name for ExperimentScore (comment #2)
- Allow ExperimentScoreFunction to return single or List of ScoreResults (comment #3)
- Move experiment score verification to verify_experiment utility (comment #4)

Backend code quality:
- Simplify TypeReference diamond operator in ExperimentScore.java (comment #5)
- Remove overloaded constructor in FeedbackScoreNames.ScoreName (comment #6)
- Reuse ScoreName instead of ScoreNameWithType in DAO (comment #7)
- Add TODO for full primary key in ORDER BY (comment #8)
- Revert flakiness fix in TemplateUtilsTest.java (comment #9)

* Update return type of get_experiment_data method to use rest_api_types for consistency

* Revision 10: Add full primary key to ORDER BY clause

* Refactor test for standard deviation calculation in experiment scoring functions

Replaced hardcoded expected standard deviation value with a dynamic calculation using the statistics.stdev function for improved accuracy and maintainability.

* Add experiment_scores column to experiments table in migration 000048

This migration introduces a new column, experiment_scores, to the experiments table to store precomputed metrics. The column is added with a default value of an empty string. A rollback statement is also included to drop the column if necessary.

* Update import statement for Prompt in evaluator.py to reflect new module structure

* Refactor whitespace in verifiers.py for improved readability

This commit removes unnecessary blank lines in the verify_experiment and _verify_experiment_scores functions, enhancing the overall clarity of the code without altering functionality.

* Enhance type hinting in dataset and experiment modules

This commit adds future annotations to the dataset REST operations and introduces TYPE_CHECKING for conditional imports in the experiment module, improving type hinting and code clarity without affecting functionality.

* Update documentation to replace `experiment_scores` with `experiment_scoring_functions` for consistency across evaluation methods

* Refactor score type handling in experiment feedback components

This commit replaces string literals for score types with constants, enhancing type safety and code clarity across various components, including ExperimentFeedbackScoresTab, ExperimentItemsTab, and related utility functions. The changes ensure consistent usage of SCORE_TYPE_FEEDBACK and SCORE_TYPE_EXPERIMENT throughout the codebase.

* Refactor column mapping for sorting functionality

This commit consolidates the logic for converting underscore-prefixed column IDs to dot notation into a single array of sortable prefixes. The `mapComplexColumn` function is updated to iterate over this array, improving code clarity and maintainability while ensuring consistent handling of various column types.

* Implement ExperimentScoreListCell and refactor score handling in data tables

This commit introduces the new ExperimentScoreListCell component for displaying experiment scores and updates the relevant data tables to utilize this component. Additionally, it refactors the handling of score types across various components, replacing string literals with constants for improved type safety and consistency. The changes affect the ExperimentsPage, ProjectsPage, and other related components, ensuring a unified approach to score type management.

* Refactor FeedbackScoresChartsWrapper and FeedbackScoreHoverCard for consistency

This commit updates the FeedbackScoresChartsWrapper component to rename the `isAggregationScores` prop to `areAggregatedScores` for improved clarity. Additionally, it modifies the subtitle text in the FeedbackScoreHoverCard component to use "Aggregated experiment scores" and "Average feedback scores" for consistency in terminology across the application.

* Add experiment scores tab to CompareExperimentsPage and update score handling

This commit introduces a new tab for displaying experiment scores in the CompareExperimentsPage. It updates the ExperimentFeedbackScoresTab component to handle both feedback and experiment scores based on the selected tab. The score retrieval logic is modified to filter scores according to their type, enhancing clarity and usability in the comparison of experiments.

* run fern generate

* Refactor score handling in various components to unify feedback and experiment score logic. Removed experiment score references and updated feedback score components to handle aggregated scores. Adjusted column definitions and metadata across multiple pages for consistency.

* Add migration to include experiment_scores column in experiments table

---------

Co-authored-by: Daniel Dimenshtein <danield@comet.com>
Co-authored-by: Ido Berkovich <ido@comet.com>
Co-authored-by: Boris Feld <boris@comet.com>
Co-authored-by: YarivHashaiComet <yarivh@comet.com>
YarivHashaiComet added a commit that referenced this pull request Dec 30, 2025
- Fix #1: Add totalCount > 0 guard to prevent '1/0 reviewed' display
- Fix #2: Add 'Done reviewing' button to exit review mode back to completion
- Fix #3: Clamp reviewedCount to 0 when queue is empty
YarivHashaiComet added a commit that referenced this pull request Dec 30, 2025
- Add 'review my annotations' link on completion screen using Button component
- Implement review mode with orange progress bar showing current position
- Add unsaved changes confirmation dialog for Next/Previous navigation
- Review progress bar displays current item position (updates on navigation)
- Submit & Complete saves changes and moves to next item
- Next/Previous buttons show warning dialog if there are unsaved changes
- Use design system colors (Button variant='link') instead of hardcoded values
- Add aria-labels to all navigation buttons for accessibility

Revision 2: Address PR review comments

- Fix #1: Add totalCount > 0 guard to prevent '1/0 reviewed' display
- Fix #2: Add 'Done reviewing' button to exit review mode back to completion
- Fix #3: Clamp reviewedCount to 0 when queue is empty

Revision 3: Change review link to outline button with proper capitalization

Revision 4: Add unsaved changes guard to Done reviewing button

Fixes baz-reviewer comment: Done reviewing button now checks for
unsaved changes and shows confirmation dialog before exiting review
mode, consistent with Next/Previous button behavior.
YarivHashaiComet added a commit that referenced this pull request Jan 20, 2026
- Fix #1: Use trace provider when model not found (provider fallback)
- Fix #3: Add role mapping for external roles (tool, function, human, etc.)
- Fix #4: Support 'type' property for LangChain/LangGraph messages
- Fix #6: Add empty array check in canOpenInPlayground
- Fix #7: Check span input before using, fallback to trace input
- Fix #9/#10: Handle { messages: [] } case properly
JetoPistola added a commit that referenced this pull request Mar 19, 2026
…onUtils, SQL cleanup

- Use JsonUtils.readValue() instead of getMapper().readValue() (comment #1)
- Replace explicit CAST with tuple() in SQL for type flexibility (comments #2, #3)
- Change passed column from UInt8 to Enum8('passed'=0,'failed'=1) (comment #4)
- Add AssertionStatus enum used end-to-end from DB to API response
- Update all SQL queries using toFloat64(passed) to toFloat64(passed = 'passed')
- Add project_id filter to assertion_results query in DatasetItemVersionDAO (comment #6)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
andrescrz added a commit that referenced this pull request Mar 19, 2026
* [OPIK-4942] [BE] POC: Separate assertion_results table (Option E)

Demonstrates the architecture for storing assertion results in a dedicated
ClickHouse table instead of piggybacking on feedback_scores with
category_name='suite_assertion'.

Changes:
- New assertion_results ClickHouse table (migration 000070)
- AssertionResultDAO for writing assertion data to the new table
- FeedbackScoreDAO splits writes: assertions -> assertion_results, regular -> feedback_scores
- ExperimentItemDAO STREAM query adds assertion_results_per_trace CTE
- ExperimentItemMapper passes assertions_array to enrichWithAssertions
- AssertionResultMapper reads from dedicated column instead of partitioning feedback scores

Not included in this POC (would be needed for production):
- DatasetItemDAO/DatasetItemVersionDAO assertion CTE changes
- ExperimentAggregatesDAO pass rate aggregation from new table
- REST endpoint exclude_category_names cleanup
- Data migration for existing installations
- SDK changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Fix test compilation: inline suite_assertion constant

The SUITE_ASSERTION_CATEGORY constant was removed from AssertionResultMapper
in the Option E refactor, but the test still referenced it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Add assertion_results_per_trace CTE to compare endpoint

- Add assertion_results_per_trace CTE to DatasetItemVersionDAO (both
  has_aggregated and has_raw branches) — compare endpoint was using
  DatasetItemVersionDAO, not DatasetItemDAO which had the CTE
- Add arp.assertions_array at tuple index 19 in both branches
- Remove group.size() <= 1 guard in AssertionResultMapper.computeRunSummaries()
  so run summaries are emitted when a dataset item has 1 run per experiment
- Add assertion_scores_avg Map column to experiment_aggregates (migration 000071)
- Add AssertionScoreAverage API record

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Revert package-lock.json — unintentional change from lint hook

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Fix test compilation errors

- AssertionResultMapperTest: update enrichWithAssertions calls to use
  (item, jsonString) signature; rewrite tests for assertion_results
  table approach (no longer reads from feedbackScores); update
  computeRunSummaries_singleRun test to reflect removed group.size()<=1 guard
- ExperimentsResourceTest: remove extra null arg from getFeedbackScoreNames
  calls (leftover from older branch version of the method)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Bump migration numbers to 071 and 072

000070 conflicts with 000070_add_project_id_to_experiments.sql from main.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Use JsonUtils import in AssertionResultMapper

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Update test: runSummaries emitted for single-run suite experiments

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Remove misleading comment from runSummaries test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Narrow catch to JsonProcessingException in AssertionResultMapper

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Add assertionScores to EXPERIMENT_IGNORED_FIELDS in test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Add assertionScores assertions to PassRate tests + fix score routing

- Add .categoryName("suite_assertion") to PassRate.score() helper so
  scores route to assertion_results table (required for pass rate SQL)
- Fix itemThreshold test: set per-item executionPolicy in createDatasetItems
  instead of applyDatasetItemChanges to avoid version-2 row-ID mismatch
- Add assertionScores assertions to 4 tests: thenReturnPassRate (2/3),
  multipleAssertions (scoreName1=1.0, scoreName2=0.5), passThresholdNotMet
  (1/3), and itemThreshold (4/6)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Address PR review comments: AssertionStatus enum, JsonUtils, SQL cleanup

- Use JsonUtils.readValue() instead of getMapper().readValue() (comment #1)
- Replace explicit CAST with tuple() in SQL for type flexibility (comments #2, #3)
- Change passed column from UInt8 to Enum8('passed'=0,'failed'=1) (comment #4)
- Add AssertionStatus enum used end-to-end from DB to API response
- Update all SQL queries using toFloat64(passed) to toFloat64(passed = 'passed')
- Add project_id filter to assertion_results query in DatasetItemVersionDAO (comment #6)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Fix test compilation: use AssertionStatus enum instead of boolean assertions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Add AssertionResultService + fix toJSONString tuple serialization

Move assertion score routing from FeedbackScoreDAO to service layer via
dedicated AssertionResultService. Fix assertion_results query where
toJSONString(tuple(...)) produced arrays instead of objects — use CAST
with named Tuple type so toJSONString emits JSON objects matching
AssertionResultRow record.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Remove suite_assertion exclusion tests from Traces and Projects

suite_assertion scores now go to the separate assertion_results table,
so exclude_category_names filtering is no longer needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Return boolean passed field in AssertionResult API response

Map AssertionStatus enum to boolean in AssertionResultMapper so
SDK/FE consumers receive passed: true/false instead of passed/failed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Andres Cruz <andresc@comet.com>
itamargolan pushed a commit that referenced this pull request Mar 25, 2026
* [OPIK-4942] [BE] POC: Separate assertion_results table (Option E)

Demonstrates the architecture for storing assertion results in a dedicated
ClickHouse table instead of piggybacking on feedback_scores with
category_name='suite_assertion'.

Changes:
- New assertion_results ClickHouse table (migration 000070)
- AssertionResultDAO for writing assertion data to the new table
- FeedbackScoreDAO splits writes: assertions -> assertion_results, regular -> feedback_scores
- ExperimentItemDAO STREAM query adds assertion_results_per_trace CTE
- ExperimentItemMapper passes assertions_array to enrichWithAssertions
- AssertionResultMapper reads from dedicated column instead of partitioning feedback scores

Not included in this POC (would be needed for production):
- DatasetItemDAO/DatasetItemVersionDAO assertion CTE changes
- ExperimentAggregatesDAO pass rate aggregation from new table
- REST endpoint exclude_category_names cleanup
- Data migration for existing installations
- SDK changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Fix test compilation: inline suite_assertion constant

The SUITE_ASSERTION_CATEGORY constant was removed from AssertionResultMapper
in the Option E refactor, but the test still referenced it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Add assertion_results_per_trace CTE to compare endpoint

- Add assertion_results_per_trace CTE to DatasetItemVersionDAO (both
  has_aggregated and has_raw branches) — compare endpoint was using
  DatasetItemVersionDAO, not DatasetItemDAO which had the CTE
- Add arp.assertions_array at tuple index 19 in both branches
- Remove group.size() <= 1 guard in AssertionResultMapper.computeRunSummaries()
  so run summaries are emitted when a dataset item has 1 run per experiment
- Add assertion_scores_avg Map column to experiment_aggregates (migration 000071)
- Add AssertionScoreAverage API record

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Revert package-lock.json — unintentional change from lint hook

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Fix test compilation errors

- AssertionResultMapperTest: update enrichWithAssertions calls to use
  (item, jsonString) signature; rewrite tests for assertion_results
  table approach (no longer reads from feedbackScores); update
  computeRunSummaries_singleRun test to reflect removed group.size()<=1 guard
- ExperimentsResourceTest: remove extra null arg from getFeedbackScoreNames
  calls (leftover from older branch version of the method)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Bump migration numbers to 071 and 072

000070 conflicts with 000070_add_project_id_to_experiments.sql from main.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Use JsonUtils import in AssertionResultMapper

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Update test: runSummaries emitted for single-run suite experiments

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Remove misleading comment from runSummaries test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Narrow catch to JsonProcessingException in AssertionResultMapper

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Add assertionScores to EXPERIMENT_IGNORED_FIELDS in test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Add assertionScores assertions to PassRate tests + fix score routing

- Add .categoryName("suite_assertion") to PassRate.score() helper so
  scores route to assertion_results table (required for pass rate SQL)
- Fix itemThreshold test: set per-item executionPolicy in createDatasetItems
  instead of applyDatasetItemChanges to avoid version-2 row-ID mismatch
- Add assertionScores assertions to 4 tests: thenReturnPassRate (2/3),
  multipleAssertions (scoreName1=1.0, scoreName2=0.5), passThresholdNotMet
  (1/3), and itemThreshold (4/6)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Address PR review comments: AssertionStatus enum, JsonUtils, SQL cleanup

- Use JsonUtils.readValue() instead of getMapper().readValue() (comment #1)
- Replace explicit CAST with tuple() in SQL for type flexibility (comments #2, #3)
- Change passed column from UInt8 to Enum8('passed'=0,'failed'=1) (comment #4)
- Add AssertionStatus enum used end-to-end from DB to API response
- Update all SQL queries using toFloat64(passed) to toFloat64(passed = 'passed')
- Add project_id filter to assertion_results query in DatasetItemVersionDAO (comment #6)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Fix test compilation: use AssertionStatus enum instead of boolean assertions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Add AssertionResultService + fix toJSONString tuple serialization

Move assertion score routing from FeedbackScoreDAO to service layer via
dedicated AssertionResultService. Fix assertion_results query where
toJSONString(tuple(...)) produced arrays instead of objects — use CAST
with named Tuple type so toJSONString emits JSON objects matching
AssertionResultRow record.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Remove suite_assertion exclusion tests from Traces and Projects

suite_assertion scores now go to the separate assertion_results table,
so exclude_category_names filtering is no longer needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* [OPIK-4942] [BE] Return boolean passed field in AssertionResult API response

Map AssertionStatus enum to boolean in AssertionResultMapper so
SDK/FE consumers receive passed: true/false instead of passed/failed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Andres Cruz <andresc@comet.com>
ldaugusto added a commit that referenced this pull request Mar 26, 2026
- Use per-workspace cursors in deleteSmallBatch via deleteForRetentionBounded
  instead of collapsing to min(cursor) across all workspaces (#1)
- Add @nonnull on executeCatchUpCycle(now) parameter (#3)
- Log when catch-up is disabled (#3)
- Run all three tiers independently per cycle via Flux.concat instead of
  switchIfEmpty chain to prevent medium/large starvation (#4)
- Return null cursor when velocity=0, marking catch-up done immediately (#5)
- Preserve Instant directly instead of UUID round-trip in deleteOneChunk (#7)
- Hoist computeSlidingWindowStart out of per-rule loop (#8)
- Centralize extractInstant/compareUUID into RetentionUtils (#9)
- Remove unnecessary @UseStringTemplateEngine from catch-up queries (#10)
- Add explicit IS NOT NULL guard on catch_up_velocity queries (#11)
- Drop unused cnt column from scout query (#14)
- Fix Javadoc: 'oldest span ID' → 'oldest span time' in SpanDAO
ldaugusto added a commit that referenced this pull request Mar 26, 2026
* [OPIK-4891] [BE] Catch-up job for apply-to-past retention rules

Progressive historical data deletion for rules with applyToPast=true.
Estimates workspace span velocity at rule creation to triage into
small/medium/large tiers with appropriate chunk sizes.

Schema:
- Add catch_up_velocity, catch_up_cursor, catch_up_done columns
- Add idx_catch_up_pending composite index for catch-up queries

Velocity estimation:
- ClickHouse query: uniq(id) / weeks_active for spans below cutoff
- Handles TOO_MANY_ROWS (code 158) by defaulting to 1M/week
- Handles empty tables gracefully

Catch-up tiers (configurable thresholds):
- Small (<10K/week): batch up to 200, one-shot delete entire range
- Medium (10K-100K/week): 10 most outdated, 7-day chunks each
- Large (>100K/week): 1 most outdated, 2-day chunks

Execution:
- Runs after regular sliding-window pass in RetentionPolicyJob
- Priority: small first (quick wins), then medium, then large
- Cursor advances oldest→newest, marks done when reaching sliding window

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix large workspace chunk size: 2 days to 1 day

Large workspaces (>100K spans/week) process one day per catch-up
cycle, so each execution handles a manageable amount of data.

* Address PR review: fix type cast, null safety, error handling

- Fix Float64→Long ClassCastException: wrap velocity query with toUInt64()
- Fix null cursor NPE in deleteSmallBatch: filter nulls before min()
- Fix catch-up marking done on delete failure: remove onErrorResume,
  propagate errors so cursor/done only advances on success
- Make markDone/updateCursor non-blocking: wrap in Mono.fromRunnable
  on boundedElastic to avoid blocking Reactor threads

* Add config comments for catch-up settings

* Return oldest span time from velocity estimation, add scouting

- Velocity query now returns both spans_per_week and oldest_span_time
- Cursor starts at the actual oldest data, not service start date
- For huge workspaces (TOO_MANY_ROWS), scout month by month on traces
  table to find first day with data, avoiding months of no-op deletes
- If a monthly scout also hits row limit, use that month start as cursor

* Replace SQL string concatenation with @BindList in markCatchUpDoneBatch

Avoids fragile raw SQL construction pattern. Uses JDBI's @BindList
for parameterized IN clause, consistent with other DAOs in the codebase.

* Address review: rename vars for clarity, hide internal fields, add safety comment

- Rename upperBound/lowerBound to cutoffId/fromId in deleteSmallBatch
  for consistency with deleteOneChunk and DAO signatures
- Hide catchUpVelocity and catchUpCursor from API response (internal);
  only catchUpDone remains public as user-facing progress indicator
- Add comment explaining NULL cursor safety in catch-up DAO queries

* Guard cursor >= upperBound, isolate catch-up errors, expose cursor in API

- Skip delete and mark done if cursor already past sliding window boundary
- Wrap catch-up cycle in onErrorResume so failures don't kill regular retention
- Re-expose catchUpCursor in API (useful for users to see cleanup progress);
  catchUpVelocity remains hidden (internal implementation detail)

* Revert scouting to simple blocking loop, improve schema comments

- Revert scoutFirstDataCursor from Flux back to blocking while-loop.
  Rule creation is a rare admin op; reactive complexity not justified.
- Improve catch_up_cursor and catch_up_done column comments to
  document cursor semantics (data before cursor has been deleted).

* Add unit tests for TOO_MANY_ROWS velocity estimation fallback

- RetentionRuleServiceVelocityTest: 6 tests covering the code 158
  exception path with mocked SpanDAO/TraceDAO. Tests scouting
  month-by-month, dense month fallback, service start date fallback,
  and non-158 exception rethrow.
- Remove large workspace integration test (max_rows_to_read profile
  setting also blocks normal inserts/deletes, making it impossible
  to trigger TOO_MANY_ROWS only on the estimation query)
- Keep small workspace catch-up integration test and applyToPast=false
  test in RetentionPolicyServiceTest
- Make estimateVelocity/scoutFirstDataCursor package-visible for testing

* Mark catch-up done when scouting finds no historical data

When the velocity estimation hits TOO_MANY_ROWS and scouting scans
every month without finding data, return velocity=0 with null cursor
so the rule is created with catchUpDone=true. Prevents hundreds of
empty 1-day chunk DELETE cycles.

* Bump migration to 000061, simplify index, split rollback

- Rename migration from 000060 to 000061 (main advanced past 000060)
- Simplify index to (catch_up_done, catch_up_velocity) since
  catch_up_done=false already implies enabled=true and apply_to_past=true
- Split rollback into individual DROP COLUMN statements

* Address review comments from thiagohora and baz

- Use per-workspace cursors in deleteSmallBatch via deleteForRetentionBounded
  instead of collapsing to min(cursor) across all workspaces (#1)
- Add @nonnull on executeCatchUpCycle(now) parameter (#3)
- Log when catch-up is disabled (#3)
- Run all three tiers independently per cycle via Flux.concat instead of
  switchIfEmpty chain to prevent medium/large starvation (#4)
- Return null cursor when velocity=0, marking catch-up done immediately (#5)
- Preserve Instant directly instead of UUID round-trip in deleteOneChunk (#7)
- Hoist computeSlidingWindowStart out of per-rule loop (#8)
- Centralize extractInstant/compareUUID into RetentionUtils (#9)
- Remove unnecessary @UseStringTemplateEngine from catch-up queries (#10)
- Add explicit IS NOT NULL guard on catch_up_velocity queries (#11)
- Drop unused cnt column from scout query (#14)
- Fix Javadoc: 'oldest span ID' → 'oldest span time' in SpanDAO

* Remove scripts/.gitignore, lower disabled log to DEBUG

- Remove unnecessary .gitignore in scripts/ (test CSVs are local only)
- Lower catch-up disabled log from INFO to DEBUG to avoid 48 noisy
  log lines per day when catch-up is off

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
JetoPistola added a commit that referenced this pull request Apr 14, 2026
- Remove useMemo on hardcoded title string (#2)
- Reset broadcast.action to null on individual toggle so allExpanded
  doesn't get stuck (#3)
- Preserve multimodal content array in handleChangeMessage — only
  update text parts, keep image/video/audio intact (#5)
- Extract AutoResizeTextarea component to deduplicate inline
  auto-sizing logic from BlueprintChatMessages and
  BlueprintValuePromptCompact (#6)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
JetoPistola added a commit that referenced this pull request Apr 14, 2026
… flow (#6219)

* [OPIK-5622] [FE] feat: revamp agent configuration version UI and edit flow

Introduce a shared CollapsibleField component (with expand-all/collapse-all
controller) used across the agent configuration detail view, the new side-panel
edit flow, and the agent sandbox. Single-line values render expanded; multi-line
values collapse by default.

On the configuration page, editing a version now opens an 872px side panel with
a sticky header, notes textarea, collapsible fields, and a sticky action bar.
The diff view is toggled in-place within the same panel (Show diff / Back to
edit) and "Save as new version" works from either view. Version notes truncate
with Show more in the read-only detail view.

In the sandbox, the Configuration tab adopts the same field component, shows an
"Unsaved changes" tag, and exposes an explicit "Save configuration" action
which surfaces a confirmation toast linking back to the Agent configuration
page. Obsolete SaveVersionDialog and unused BlueprintDiffDialog wrapper removed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(agent-config): polish version UI per Figma feedback

Restructure field rendering to match the Figma hierarchy: the outer
field header (type icon + name + info) now sits without card chrome on
the surface, while bordered CollapsibleBlocks act as the collapsible
units underneath. Chat prompts render each message (System, Prompt,
etc.) as its own labeled CollapsibleBlock via a new
BlueprintValuePromptCompact + BlueprintChatMessages component pair, so
agent-configuration views no longer reuse the playground prompt chrome.

Apply remaining UI feedback: gray icons on Deploy to / Edit
configuration, "Deploy to..." copy with circle-fading-arrow-up icon,
in-place Show diff / Back to edit toggle with git-compare and undo-2
icons, "Compare {name} -> current changes" header, "Add version notes"
textarea above the Edit fields row, 48px panel header, save
configuration button with save + arrow-up-right icons, "Edited"
indicator with red dot replacing the orange tag, save toast wired to
the new blueprint id so it reads "You have created {versionName}",
focus-within highlight on collapsible blocks, scrollbar-gutter stable
on the configuration page, descriptions always shown in the diff
table, bare scalar editors (no card) for non collapsible fields in
edit mode, and a broadcast-driven Expand all / Collapse all that also
fans out to prompt chat messages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(agent-config): UX review — typography, button styling, prompt editing

- Panel header + "Edit fields" title: comet-body-accented (16px) instead of 14px
- Expand/collapse icon inherits button text color (no longer looks disabled)
- Detail view: override text-foreground on expand/collapse wrapper
- Editable prompts: white card background, borderless auto-sizing textarea
- Spacing: 1rem between textarea and Edit fields heading

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(agent-config): address baz-reviewer feedback

- Remove useMemo on hardcoded title string (#2)
- Reset broadcast.action to null on individual toggle so allExpanded
  doesn't get stuck (#3)
- Preserve multimodal content array in handleChangeMessage — only
  update text parts, keep image/video/audio intact (#5)
- Extract AutoResizeTextarea component to deduplicate inline
  auto-sizing logic from BlueprintChatMessages and
  BlueprintValuePromptCompact (#6)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(agent-config): add message management actions to chat prompt editor

Editable chat messages now support: role selector dropdown (System /
User / Assistant), move up/down reordering, duplicate, delete, and
"Add message" button. CollapsibleBlock gains trailing and headerPrefix
props to host these controls in the header row.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(agent-config): auto-resize on controlled value + type=button on drag handle

- AutoResizeTextarea: useEffect keyed on value recalculates height
  so external value changes (e.g. expand all) don't clip content
- Drag handle button: add type="button" to prevent form submission

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(agent-config): rename Add message to Message, remove config page toast

- Button label: "Message" instead of "Add message" (plus icon provides context)
- Remove toast from config page save (only sandbox shows toast per spec)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
thiagohora added a commit that referenced this pull request Apr 17, 2026
…drop filter strip

The strip helper (withoutTraceThreadIdPushdown) caused two problems:
- bindTraceThreadSearchCriteria still iterated the full filter list with
  TRACE_THREAD strategy, trying to bind :filter0 for the ID filter that
  newTraceThreadFindTemplate had emitted against the stripped list. The
  SQL had no :filter0 placeholder → R2DBC "non-existing identifier" and
  thread-stats endpoint 500'd when filtered by thread id.
- TraceDAO callers of the same helper silently lost ID filters (baz #3).

Since thread_id is stable per trace (the same invariant the pushdown
optimization relies on), applying the filter at both positions — the
outer aggregate (via the normal TRACE_THREAD strategy) and the inner
raw scan (via :thread_id_pushdown) — is idempotent. The inner predicate
still unlocks idx_traces_thread_id_bf; the outer becomes a no-op on an
already-single-thread result set.

Simpler code, no strip helper needed, stats test passes.
thiagohora added a commit that referenced this pull request Apr 20, 2026
…wn thread_id filter (#6358)

* [OPIK-5973] [BE] perf: optimize thread list/count queries and push down thread_id filter

Thread list/count queries rewritten to use LIMIT 1 BY instead of FINAL on
traces, spans, and trace_threads. Narrow the traces_final projection and
add a separate traces_final_ids CTE so downstream CTEs (spans_deduped,
trace_threads_final) subset via IN(id) rather than wide-row deduplication.
Benchmark on production-equivalent data: ~3× faster, ~2.8× less memory.

Split TraceThreadField.ID=EQUAL filters out of the outer trace_thread_filters
and emit them against traces.thread_id inside traces_final_ids, so
idx_traces_thread_id_bf can prune granules. Parameter :thread_id_pushdown
is bound separately to avoid colliding with strategy-generated :filter{i}
names.

Rename ThreadService → TraceThreadQueryService and split the trace-thread
filter helpers out of DatabaseUtils into a dedicated FilterUtils class.

* [OPIK-5973] [BE] fix: update remaining callers after ThreadService/DatabaseUtils renames

Missed in the previous commit — OpikApplication, TracesResource, and
AssertionResultDAO all reference the old names and break compile.
Swap imports and callsites to match the renamed classes.

* [OPIK-5973] [BE] chore: add SETTINGS log_comment to thread queries

Attaches log_comment to list, count, findById, search, and stats thread
queries so they can be traced in ClickHouse query logs with the query name,
workspace_id, user_name, and per-call details. Follows the same pattern
used across the other DAOs.

Restructured each method to put makeMonoContextAware / makeFluxContextAware
at the outermost level so userName / workspaceId are available before
template rendering. countThreadTotal now takes those values as parameters
instead of wrapping in its own context lookup.

* Fix filters

* [OPIK-5973] [BE] fix: apply TraceThreadField.ID pushdown additively; drop filter strip

The strip helper (withoutTraceThreadIdPushdown) caused two problems:
- bindTraceThreadSearchCriteria still iterated the full filter list with
  TRACE_THREAD strategy, trying to bind :filter0 for the ID filter that
  newTraceThreadFindTemplate had emitted against the stripped list. The
  SQL had no :filter0 placeholder → R2DBC "non-existing identifier" and
  thread-stats endpoint 500'd when filtered by thread id.
- TraceDAO callers of the same helper silently lost ID filters (baz #3).

Since thread_id is stable per trace (the same invariant the pushdown
optimization relies on), applying the filter at both positions — the
outer aggregate (via the normal TRACE_THREAD strategy) and the inner
raw scan (via :thread_id_pushdown) — is idempotent. The inner predicate
still unlocks idx_traces_thread_id_bf; the outer becomes a no-op on an
already-single-thread result set.

Simpler code, no strip helper needed, stats test passes.

* [OPIK-5973] [BE] refactor: align thread list/count queries with TraceDAO prefilter pattern

Mirrors TraceDAO#shouldUseTraceIdPrefilter / trace_id_prefilter shape on
the thread list and count queries:

- traces_final_ids is now conditional (<if(traces_final_ids)>) — only
  emitted when filters/search narrow beyond the workspace/project/uuid-
  range scope, via new shouldUseTracesFinalIdsPrefilter() helper.
- Dropped the inner ORDER BY … LIMIT 1 BY id inside traces_final_ids;
  it's now SELECT DISTINCT id, thread_id with filters inline. Accepts
  phantom reads at the prefilter level — authoritative filtering happens
  downstream.
- traces_final wraps in a two-level subquery so filters/search_text are
  re-applied after the LIMIT 1 BY id dedup, dropping phantom rows whose
  latest version no longer matches.
- Downstream CTEs (traces_final, spans_deduped, trace_threads_final) now
  branch via <if(traces_final_ids)>…<else> <if(uuid_from_time)>…<endif>
  <endif>, scoping to the ID set when the prefilter is active, otherwise
  applying the uuid range directly.
- Applied to list and count queries. Stats query has different shape
  (still on FINAL) and doesn't use traces_final_ids; unchanged here.

* [OPIK-5973] [BE] refactor: simplify count query, LIMIT 1 BY id, doc pushdown operator scope

- Count query: drop spans_deduped/spans_agg/feedback_scores_agg CTEs and
  their joins, drop display-only columns (total_estimated_cost, usage,
  feedback_scores_list, feedback_scores). Mirrors TraceDAO#COUNT_BY_PROJECT_ID
  — only CTEs needed for filter evaluation remain. All filter paths
  preserved (TRACE-level, trace_thread_filters, feedback_scores_filters,
  feedback_scores_empty_filters, annotation_queue_filters).

- spans_deduped LIMIT 1 BY: switch from full sort-key tuple
  (workspace_id, project_id, trace_id, parent_span_id, id) to id alone.
  Span id is UUID v7 globally unique, so the shorter key is equivalent
  and reads more clearly.

- Indent the <if(traces_final_ids)> / <else> branches one level deeper
  inside traces_final, spans_deduped, and trace_threads_final so the
  conditional structure is visually aligned with its nesting.

- FilterUtils.findTraceThreadIdPushdownFilter: add a comment explaining
  why the check is scoped to Operator.EQUAL — the pushdown SQL template
  is hardcoded to thread_id = :x, and only EQUAL benefits from the
  traces.thread_id bloom filter. Locks intent for future contributors.

* [OPIK-5973] [BE] refactor: align stats query with list/count FINAL→LIMIT 1 BY pattern

SELECT_TRACE_THREADS_STATS now mirrors list/count structure:

- Replace FROM traces final / FROM spans final / FROM trace_threads FINAL
  with LIMIT 1 BY id patterns.
- Add conditional traces_final_ids prefilter (gated by
  shouldUseTracesFinalIdsPrefilter) with <if(traces_final_ids)>…<else>
  <if(uuid_from_time)>…<endif> <endif> branches in traces_final,
  spans_deduped, and trace_threads_final.
- Split spans_deduped → spans_agg so the narrow dedup runs before the
  per-thread aggregation. LIMIT 1 BY id (consistent with spans_deduped
  simplification elsewhere).
- traces_final wraps in a two-level subquery so <filters> / <search_text>
  re-apply post-dedup (drops phantom reads).
- Wire shouldUseTracesFinalIdsPrefilter in getThreadStats.

* [OPIK-5973] [BE] fix: apply filters once in traces_final_ids prefilter

Restructures the traces_final_ids CTE in list/count/stats so filters and
search_text are applied on the outer SELECT DISTINCT of the prefilter rather
than being duplicated in both the prefilter and the traces_final outer
wrapper. traces_final now just dedups via LIMIT 1 BY id and projects; the
id set from traces_final_ids is authoritative for downstream spans_deduped
and trace_threads_final scans.

* [OPIK-5973] [BE] refactor: simplify trace_threads_final dedup to LIMIT 1 BY id

UUIDv7 id is globally unique, so LIMIT 1 BY id produces the same deduped
set as the full (workspace_id, project_id, thread_id, id) tuple. Aligns
list/count with the stats query which already uses LIMIT 1 BY id.

* [OPIK-5973] [BE] perf: gate feedback_scores and annotation_queue CTEs on filter usage in count query

feedback_scores_deduped → _grouped → _final and thread_annotation_queue_ids
were always materialized in the count query, even when no filter referenced
them. Their output (display-formatted category_name/reason concat,
value_by_author maps, annotation_queue_ids arrays) is not used by
count(DISTINCT id), only by the inner filter predicates that may or may not
be present.

Gated via <if(feedback_scores_needed)> (OR of feedback_scores_filters and
feedback_scores_empty_filters) and <if(annotation_queue_filters)>. The
common-path count (no feedback-score filter, no annotation-queue filter)
now skips the feedback_scores union-all + two-level groupArray pipeline
and the annotation_queue_items join entirely.
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