Skip to content

TRT-2741: Phase 2 - Replace prow_test_report matviews with cumulative summary queries#3769

Draft
mstaeble wants to merge 1 commit into
openshift:mainfrom
mstaeble:worktree-trt-2741-phase2
Draft

TRT-2741: Phase 2 - Replace prow_test_report matviews with cumulative summary queries#3769
mstaeble wants to merge 1 commit into
openshift:mainfrom
mstaeble:worktree-trt-2741-phase2

Conversation

@mstaeble

@mstaeble mstaeble commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Replace prow_test_report_7d_matview, prow_test_report_2d_matview, and their collapsed variants with direct queries against the test_cumulative_summaries partitioned prefix sum tables introduced in Phase 1 (PR #3762). This eliminates the expensive materialized view refresh step from the server startup/refresh path.

Key changes

  • New cumulative_query.go: Core query builders using a 3-way self-join on test_cumulative_summaries (end, boundary, start dates) to compute period counts from prefix sums. Includes testReportCoreJoin (per-variant), testReportPreAgg (with metadata), and TestReportQueryCollapsed (aggregated per test).
  • DateRange type: Half-open [Start, End) intervals with PeriodsForReportType to compute sample/base periods and resolvePrefixSumDates to clamp to available data.
  • Name filter push-down: nameFilterConditions converts name filters (equals, starts-with, contains, with NOT support) directly into SQL conditions pushed into inner queries, avoiding full-table scans.
  • Variant filter push-down: variantFilterConditions generates EXISTS/NOT EXISTS subqueries against variant_combinations for raw SQL contexts.
  • Arithmetic filter push-down: processedFilterConditions pushes arithmetic comparisons (>=, <=, =, etc.) into the materialized CTE in the uncollapsed path.
  • Raw SQL for both query paths: Both collapsed and uncollapsed paths use strings.Builder + positional args for query construction, sharing the openBugsSQL constant and using the same nameFilterConditions/variantFilterConditions helpers. This eliminates duplication between GORM and raw SQL approaches.
  • Collapsed path optimization: Aggregates prefix sums per (test_id, suite_id) at each date partition separately (~16K groups), then joins three small results, avoiding the expensive 3-way self-join on all ~1.8M per-prow_job rows.
  • Removed GetDataFromCacheOrMatview: Replaced by existing GetDataFromCacheOrGenerate.
  • Removed matview definitions: pkg/db/views.go deleted; UpdateSchema no longer creates/refreshes materialized views.
  • ILIKE with metacharacter escaping: Replaces ~* regex matching for case-insensitive substring filters.

Staging performance (2026-07-16, commit 65c172e)

Deployed to staging (sippy-staging-88). All times are cold cache (Redis flushed before each test).

/api/tests endpoint

Query Time Rows
Uncollapsed, unfiltered (4.19) 1.3s 8,295
Collapsed, unfiltered (4.19) 0.5s 8,295
Uncollapsed, name contains "install" (4.19) 0.6s 188
Collapsed, name contains "install" (4.19) 0.1s 188
Negative name filter, NOT contains "install" (4.19) 1.5s 8,107
Arithmetic filter, current_pass_percentage > 90 (4.19) 1.3s 7,553
Complex mixed filters (5.0, uncollapsed) 14.3s 717

Other endpoints

Endpoint Time Result
/api/install?release=4.19 0.9s 45 tests, 87 variant columns
/api/feature_gates?release=4.19 0.2s 98 feature gates

Parity verification (staging vs production)

Ran 5 parallel parity test suites comparing staging (new cumulative query code) against production (old matview code) across releases 4.18, 4.19, and 5.0.

Methodology

Each test fetched the same API endpoint from both environments and compared row counts, test names, and field values. Staging and production have independently-refreshed databases, so data freshness differences are expected.

Results

Test Suite Verdict Details
Collapsed tests (3 releases) PASS Row count diffs (449 for 4.18, 19 for 4.19, 1041 for 5.0) traced to CI infrastructure tests not yet in staging's cumulative tables. All shared rows with matching run counts have identical computed fields.
Filtered tests (4 filter combos) PASS 920+ rows with identical run counts verified: all computed percentages match 100%. Name, negative name, arithmetic, and complex mixed filters all produce correct results.
Install report (3 releases) PASS Test name sets match. Run count diffs are data freshness.
Sorted/period tests (4 scenarios) PASS Sort order correct. Internal calculation consistency verified across all 8,295 staging rows with 0 mismatches (pass_percentage, working_percentage, net_improvement).
Uncollapsed tests (3 releases) PASS Row count diffs from data freshness. When run counts match, all computed fields match exactly.

Key finding: Across all test suites, whenever staging and production have the same underlying data (identical run counts), all computed percentages, net improvements, and derived fields match exactly. Every discrepancy traces to different data coverage between the two independently-refreshed environments.

Post-refactor parity (raw SQL conversion)

After converting the collapsed path from GORM to raw SQL, ran full parity check against the staging deployment (old GORM code, same database):

Release Rows Mismatches
4.19 8,295 0
5.0 14,117 0

Zero mismatches across all rows and all fields (runs, successes, failures, flakes, percentages, open_bugs, jira_component).

Test plan

  • go vet ./pkg/... passes
  • make lint passes (0 issues)
  • make test passes
  • make e2e passes (5/5 suites)
  • Deployed to staging, verified all API endpoints return correct data
  • Cold-cache performance validated (Redis flushed between tests)
  • 5-way parity test against production confirms calculation correctness
  • Post-refactor parity: collapsed raw SQL vs GORM, 22,412 rows, 0 mismatches

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Test reports now use dynamically calculated reporting periods, supporting more flexible date-based analysis.
    • Added improved test-name and variant filtering for report results.
    • Overall test statistics are calculated consistently across variants.
  • Bug Fixes

    • Improved handling of empty date ranges to prevent unnecessary processing.
    • Feature-gate results now better reflect tests with activity during the selected period.
  • Refactor

    • Updated reporting to use cumulative historical data, improving consistency and removing reliance on legacy report views.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: automatic mode

@openshift-ci-robot

openshift-ci-robot commented Jul 14, 2026

Copy link
Copy Markdown

@mstaeble: This pull request references TRT-2741 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Summary

  • Replace prow_test_report_7_matview and prow_test_report_2_matview with direct queries against test_cumulative_summaries partitioned prefix sum tables
  • Introduce DateRange type with half-open [Start, End) semantics and PeriodsForReportType to compute sample/base periods
  • Add resolvePrefixSumDates helper to clamp dates to available data and convert to prefix sum lookup dates
  • Use ILIKE with metacharacter escaping for case-insensitive substring matching (preserving old ~* regex semantics)
  • Remove GetDataFromCacheOrMatview (replaced by existing GetDataFromCacheOrGenerate)
  • Add zero-count filter (current_runs > 0 OR previous_runs > 0) to exclude forward-filled rows from variant reports

Test plan

  • make lint passes
  • make test passes
  • make e2e passes
  • Deploy to staging and verify /api/tests responses match production
  • Benchmark query performance against staging database

@coderabbitai ignore

🤖 Generated with Claude Code

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 14, 2026
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 14, 2026
@openshift-ci

openshift-ci Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci

openshift-ci Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: mstaeble
Once this PR has been reviewed and has the lgtm label, please assign smg247 for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

No action needed here — this is an automated notice from the openshift-ci-robot (jira-lifecycle-plugin) about the linked Jira issue's target version, not a request directed at me. Additionally, this PR includes a @coderabbitai ignore directive, so I won't be engaging further on this PR.

@mstaeble mstaeble force-pushed the worktree-trt-2741-phase2 branch from ce0aff4 to d09b3c0 Compare July 14, 2026 04:03
@mstaeble

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Test reporting is migrated from report materialized views to cumulative-summary query builders. APIs, variant queries, benchmarks, feature-gate database wiring, cache usage, and materialized-view configuration are updated accordingly.

Changes

Cumulative reporting migration

Layer / File(s) Summary
Cumulative query builders
pkg/db/query/cumulative_query.go, pkg/db/query/cumulative_query_test.go
Adds date-range handling, structured name matching, prefix-sum report queries, collapsed aggregation, metadata joins, open-bug counts, filter translation, and unit tests.
Report generation and query consumers
pkg/api/tests.go, pkg/db/query/test_queries.go, pkg/api/install.go, pkg/html/installhtml/util.go
Routes reports through cumulative queries, updates variant aggregation and filtering, computes overall results in Go, and replaces raw name filters with TestNameMatches.
Feature-gate and infrastructure wiring
pkg/db/query/feature_gates.go, pkg/sippyserver/server.go, pkg/db/cumulativesummary/cumulative_summary.go
Uses cumulative summaries for feature-gate test selection, passes the database wrapper, and adds an invalid-date-range early exit.
Materialized-view and cache cleanup
pkg/db/views.go, pkg/api/cache.go, pkg/api/cache_test.go
Removes test-report materialized views and the matview cache helper, and adds a timestamp-pointer test helper.
Benchmark and supporting updates
pkg/flags/postgres_benchmarking_test.go, pkg/dataloader/prowloader/prow.go
Updates benchmarks to build cumulative report queries and changes one debug log to structured logging.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ReportAPI
  participant TestReportQuery
  participant CumulativeSummaries
  participant ReportMetadata
  ReportAPI->>TestReportQuery: build sample/base report query
  TestReportQuery->>CumulativeSummaries: resolve dates and calculate prefix-sum differences
  TestReportQuery->>ReportMetadata: join tests, suites, ownership, variants, and open bugs
  TestReportQuery-->>ReportAPI: return report query
Loading

Possibly related PRs

Suggested reviewers: stbenjam, xueqzhan, neisw

🚥 Pre-merge checks | ✅ 18 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Go Error Handling ⚠️ Warning resolveDateRanges logs and returns on MAX(date) scan failure without propagating, and TestReportsByVariant returns raw r.Error without fmt.Errorf wrapping. Return an error from resolveDateRanges and propagate it through the query builders; wrap DB failures with fmt.Errorf(... %w) instead of returning/logging raw errors.
Test Coverage For New Features ⚠️ Warning Query helpers are tested, but new pure API logic (safePercent, computeOverallTest) and the OR/AND filter regression lack unit tests; benchmark code only logs. Add table-driven tests for safePercent/computeOverallTest and regression tests for default-AND name filters and explicit-OR variant filters in the query builders.
✅ Passed checks (18 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Sql Injection Prevention ✅ Passed PASS: New SQL paths bind user values with ? args and quote identifiers (pq.QuoteIdentifier); remaining string assembly is only static SQL fragments/aliases.
Excessive Css In React Should Use Styles ✅ Passed PR changes only backend Go files under pkg/*; no React/JSX files or inline style objects were modified, so the CSS/style guideline is not applicable.
Single Responsibility And Clear Naming ✅ Passed The new query/API helpers stay within the test-reporting domain, use descriptive names, and keep structs small; no generic or overstuffed abstractions stood out.
Feature Documentation ✅ Passed No relevant feature doc exists under docs/features; the only file there documents job-analysis symptoms, not the changed test/install/feature-gate flows.
Stable And Deterministic Test Names ✅ Passed No Ginkgo titles were added; the changed tests use fixed literal names or static table entries, with no timestamps, IDs, or generated values.
Test Structure And Quality ✅ Passed No Ginkgo tests were added or modified; the changed tests are table-driven unit/benchmark tests with explicit cleanup and no cluster waits.
Microshift Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the changed tests are standard Go unit/benchmark tests, so MicroShift-specific checks don’t apply.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo specs were added; the changed e2e files use standard testing tests and only call APIs, with no multi-node/HA assumptions.
Topology-Aware Scheduling Compatibility ✅ Passed Diff only touches API/query/report code and tests; no manifests, controllers, pod specs, affinities, selectors, or replica logic were changed, so this check is not applicable.
Ote Binary Stdout Contract ✅ Passed No added stdout writes in main/init/TestMain/suite setup; the only fmt.Print/Printf calls are inside ordinary test/benchmark helpers.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the changed tests are plain testing.T unit/benchmark code with no IPv4 literals or external-host dependencies.
No-Weak-Crypto ✅ Passed No MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, custom crypto, or non-constant-time secret comparisons appear in the touched code.
Container-Privileges ✅ Passed PASS: The PR only changes Go source files; no Kubernetes/container manifests were modified, and scans found no privileged flags in changed files.
No-Sensitive-Data-In-Logs ✅ Passed No new logs expose secrets/PII; added/changed logs only include release, test name, counts, or PR org/repo/sha metadata.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: replacing prow_test_report matviews with cumulative summary queries.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
pkg/db/query/feature_gates.go (1)

78-87: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Wrap errors with context using fmt.Errorf and %w.

As per coding guidelines, do not return unwrapped errors. Please wrap them with contextual information to aid in debugging.

🐛 Proposed fix to wrap errors
 	q, err := filter.FilterableDBResult(table, filterOpts, api.FeatureGate{})
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to apply filter: %w", err)
 	}
 
 	results := make([]api.FeatureGate, 0)
 	tx := q.Scan(&results)
 	if tx.Error != nil {
-		return nil, tx.Error
+		return nil, fmt.Errorf("failed to scan feature gates: %w", tx.Error)
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/db/query/feature_gates.go` around lines 78 - 87, Update the query flow
around FilterableDBResult and q.Scan in the relevant feature-gate function to
wrap both returned errors with contextual messages using fmt.Errorf and the %w
verb, preserving the original errors for unwrapping while identifying whether
filtering or scanning failed.

Source: Coding guidelines

🧹 Nitpick comments (2)
pkg/db/query/cumulative_query.go (2)

51-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider unit tests for the new pure helper functions.

escapeLikeMetachars, PeriodsForReportType, and resolveDateRanges are pure/deterministic and easy to unit test (date-boundary math is especially error-prone). No test file was included in this review scope for cumulative_query.go.

Also applies to: 120-142

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

In `@pkg/db/query/cumulative_query.go` around lines 51 - 54, Add unit tests for
the pure helpers escapeLikeMetachars, PeriodsForReportType, and
resolveDateRanges in cumulative_query.go. Cover LIKE metacharacter escaping,
each report type’s period behavior, and date-range boundary calculations
including representative edge cases, while keeping tests deterministic and
isolated from external dependencies.

49-254: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add inline comments for major query sections in the new builders.

testReportPreAgg, TestReportQuery, and TestReportQueryCollapsed have function-level docstrings but no inline comments marking the purpose of individual JOINs/window-function blocks (e.g., what m/s self-joins represent, why the window functions are partitioned as they are). As per path instructions, pkg/**/query/** code should have inline comments explaining each major query section (CTEs, JOINs, window functions, WHERE clauses).

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

In `@pkg/db/query/cumulative_query.go` around lines 49 - 254, Add concise inline
comments throughout TestReportQuery, testReportPreAgg, and
TestReportQueryCollapsed that identify each major query section, including
percentage/window-function calculations, openBugs and metadata joins, m/s
prefix-sum self-joins, variant filtering, aggregation, and date/release WHERE
clauses. Keep comments adjacent to the corresponding builder calls or SELECT
blocks and describe their purpose without changing query behavior.

Source: Path instructions

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

Inline comments:
In `@pkg/db/query/cumulative_query.go`:
- Around line 27-47: Update buildTestsJoinCondition so Prefixes values pass
through escapeLikeMetachars before appending the trailing wildcard, preserving
literal prefix characters while retaining prefix matching behavior. Leave
exact-name and substring handling unchanged.

---

Outside diff comments:
In `@pkg/db/query/feature_gates.go`:
- Around line 78-87: Update the query flow around FilterableDBResult and q.Scan
in the relevant feature-gate function to wrap both returned errors with
contextual messages using fmt.Errorf and the %w verb, preserving the original
errors for unwrapping while identifying whether filtering or scanning failed.

---

Nitpick comments:
In `@pkg/db/query/cumulative_query.go`:
- Around line 51-54: Add unit tests for the pure helpers escapeLikeMetachars,
PeriodsForReportType, and resolveDateRanges in cumulative_query.go. Cover LIKE
metacharacter escaping, each report type’s period behavior, and date-range
boundary calculations including representative edge cases, while keeping tests
deterministic and isolated from external dependencies.
- Around line 49-254: Add concise inline comments throughout TestReportQuery,
testReportPreAgg, and TestReportQueryCollapsed that identify each major query
section, including percentage/window-function calculations, openBugs and
metadata joins, m/s prefix-sum self-joins, variant filtering, aggregation, and
date/release WHERE clauses. Keep comments adjacent to the corresponding builder
calls or SELECT blocks and describe their purpose without changing query
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: b3e19b0b-750f-4e5a-8cd7-91a1412eabe1

📥 Commits

Reviewing files that changed from the base of the PR and between fa7e1d0 and d09b3c0.

📒 Files selected for processing (13)
  • pkg/api/cache.go
  • pkg/api/cache_test.go
  • pkg/api/install.go
  • pkg/api/tests.go
  • pkg/db/cumulativesummary/cumulative_summary.go
  • pkg/db/query/cumulative_query.go
  • pkg/db/query/feature_gates.go
  • pkg/db/query/misc_queries.go
  • pkg/db/query/test_queries.go
  • pkg/db/views.go
  • pkg/flags/postgres_benchmarking_test.go
  • pkg/html/installhtml/util.go
  • pkg/sippyserver/server.go
💤 Files with no reviewable changes (4)
  • pkg/db/query/misc_queries.go
  • pkg/api/cache.go
  • pkg/api/cache_test.go
  • pkg/db/views.go

Comment thread pkg/db/query/cumulative_query.go Outdated
@mstaeble mstaeble force-pushed the worktree-trt-2741-phase2 branch from d09b3c0 to cc82cf3 Compare July 14, 2026 12:52

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
pkg/db/query/feature_gates.go (1)

13-90: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add regression coverage for GetFeatureGatesFromDB. The new prefix-sum active-test check and the byTag/byInstall union should be covered so the query behavior stays stable.

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

In `@pkg/db/query/feature_gates.go` around lines 13 - 90, Add regression tests for
GetFeatureGatesFromDB covering both active-test detection via prefix_sum_runs
and the combined byTag/byInstall query paths. Use fixtures that distinguish
tests with actual recent runs from carried-forward rows, and verify feature-gate
and install-test results are returned correctly.

Source: Coding guidelines

🧹 Nitpick comments (2)
pkg/db/query/feature_gates.go (2)

33-42: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add inline comments for the byTag/byInstall query blocks.

As per path instructions, pkg/**/query/** query-building code should have inline comments explaining each major query section (JOINs, WHERE filters, etc.). byTag's CROSS JOIN LATERAL regexp_matches(...) and the reused activeTestExists filter in both blocks would benefit from a short comment on intent (e.g., why (m.match)[2] is the gate name, why the same active-test filter is applied to both tag- and install-derived subsets).

✏️ Example inline comments
+	// Extract [FeatureGate:x] / [OCPFeatureGate:x] tag names, keeping only tests that
+	// actually ran (not merely carried forward) in the lookup window.
 	byTag := dbc.DB.Table("tests t").
 		Select("t.name, ? AS release, (m.match)[2] AS gate_name", release).
 		Joins(`CROSS JOIN LATERAL regexp_matches(t.name, '\[(FeatureGate|OCPFeatureGate):([^\]]+)\]', 'g') AS m(match)`).
 		Where("t.name LIKE ?", "%FeatureGate:%").
 		Where(activeTestExists, lookupStart, lookupEnd, release)

+	// Install tests map to the "Install" feature gate via a NULL gate_name sentinel,
+	// matched later in fgQuery's join.
 	byInstall := dbc.DB.Table("tests t").
 		Select("t.name, ? AS release, NULL::text AS gate_name", release).
 		Where("t.name LIKE ?", "%install should succeed%").
 		Where(activeTestExists, lookupStart, lookupEnd, release)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/db/query/feature_gates.go` around lines 33 - 42, Add concise inline
comments around the byTag and byInstall query blocks explaining the gate-name
extraction from the lateral regexp match, the purpose of the CROSS JOIN LATERAL,
and why both derived subsets reuse activeTestExists with the lookup bounds. Keep
the query logic unchanged.

Source: Path instructions


23-42: 🚀 Performance & Scalability | 🔵 Trivial

Verify indexing supports the new correlated EXISTS against test_cumulative_summaries.

byTag/byInstall each do a leading-wildcard LIKE scan of tests, then run the activeTestExists correlated subquery (a self-join on test_cumulative_summaries) per matching row. Postgres can turn EXISTS into a semi-join, but that still depends on an index covering (test_id, date, release, prow_job_id, suite_id) on test_cumulative_summaries to avoid a nested-loop scan per candidate test. Given the PR description mentions staged performance validation for this endpoint, please confirm the relevant index exists (or was already validated) for this access pattern.

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

In `@pkg/db/query/feature_gates.go` around lines 23 - 42, Verify that
test_cumulative_summaries has an index supporting activeTestExists lookups
across test_id, date, release, prow_job_id, and suite_id, including the
self-join predicates. If the index is absent, add the appropriate migration or
index definition; otherwise confirm the existing index covers this correlated
EXISTS access pattern and preserve the byTag and byInstall queries.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/db/query/feature_gates.go`:
- Around line 14-21: Update the date range setup around resolveDateRanges to
request a seven-day window instead of eight, and handle the clamped-range case
where lookupStart equals lookupEnd so valid feature gates are not filtered out.
Preserve the intended comparison of cumulative runs across the actual seven-day
period while ensuring releases with no in-range cumulative data still use an
effective lookup window.

---

Outside diff comments:
In `@pkg/db/query/feature_gates.go`:
- Around line 13-90: Add regression tests for GetFeatureGatesFromDB covering
both active-test detection via prefix_sum_runs and the combined byTag/byInstall
query paths. Use fixtures that distinguish tests with actual recent runs from
carried-forward rows, and verify feature-gate and install-test results are
returned correctly.

---

Nitpick comments:
In `@pkg/db/query/feature_gates.go`:
- Around line 33-42: Add concise inline comments around the byTag and byInstall
query blocks explaining the gate-name extraction from the lateral regexp match,
the purpose of the CROSS JOIN LATERAL, and why both derived subsets reuse
activeTestExists with the lookup bounds. Keep the query logic unchanged.
- Around line 23-42: Verify that test_cumulative_summaries has an index
supporting activeTestExists lookups across test_id, date, release, prow_job_id,
and suite_id, including the self-join predicates. If the index is absent, add
the appropriate migration or index definition; otherwise confirm the existing
index covers this correlated EXISTS access pattern and preserve the byTag and
byInstall queries.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 691d4a7e-7f66-4a54-b44f-72dfdfd7e967

📥 Commits

Reviewing files that changed from the base of the PR and between d09b3c0 and cc82cf3.

📒 Files selected for processing (13)
  • pkg/api/cache.go
  • pkg/api/cache_test.go
  • pkg/api/install.go
  • pkg/api/tests.go
  • pkg/db/cumulativesummary/cumulative_summary.go
  • pkg/db/query/cumulative_query.go
  • pkg/db/query/feature_gates.go
  • pkg/db/query/misc_queries.go
  • pkg/db/query/test_queries.go
  • pkg/db/views.go
  • pkg/flags/postgres_benchmarking_test.go
  • pkg/html/installhtml/util.go
  • pkg/sippyserver/server.go
💤 Files with no reviewable changes (4)
  • pkg/db/query/misc_queries.go
  • pkg/db/views.go
  • pkg/api/cache.go
  • pkg/api/cache_test.go
🚧 Files skipped from review as they are similar to previous changes (8)
  • pkg/db/cumulativesummary/cumulative_summary.go
  • pkg/html/installhtml/util.go
  • pkg/db/query/cumulative_query.go
  • pkg/sippyserver/server.go
  • pkg/api/tests.go
  • pkg/api/install.go
  • pkg/flags/postgres_benchmarking_test.go
  • pkg/db/query/test_queries.go

Comment thread pkg/db/query/feature_gates.go
@mstaeble mstaeble force-pushed the worktree-trt-2741-phase2 branch from cc82cf3 to 7d81fe6 Compare July 14, 2026 13:02
@openshift-ci openshift-ci Bot added the ready-for-human-review Indicates a PR has been reviewed by automated tools and is ready for human review label Jul 14, 2026
@mstaeble mstaeble changed the title [WIP] TRT-2741: Phase 2 - Replace prow_test_report matviews with cumulative summary queries TRT-2741: Phase 2 - Replace prow_test_report matviews with cumulative summary queries Jul 14, 2026
@mstaeble mstaeble marked this pull request as ready for review July 14, 2026 13:07
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 14, 2026
@openshift-ci openshift-ci Bot requested review from neisw and stbenjam July 14, 2026 13:07
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling required tests:
/test e2e

@openshift-ci

openshift-ci Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

@mstaeble: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@mstaeble mstaeble changed the title TRT-2741: Phase 2 - Replace prow_test_report matviews with cumulative summary queries [WIP] TRT-2741: Phase 2 - Replace prow_test_report matviews with cumulative summary queries Jul 14, 2026
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 14, 2026
@mstaeble mstaeble marked this pull request as draft July 14, 2026 17:10
@mstaeble mstaeble force-pushed the worktree-trt-2741-phase2 branch 3 times, most recently from 730ec83 to e2513ef Compare July 14, 2026 17:42
@mstaeble mstaeble force-pushed the worktree-trt-2741-phase2 branch from 3880ecb to 65c172e Compare July 16, 2026 03:04
@mstaeble mstaeble changed the title [WIP] TRT-2741: Phase 2 - Replace prow_test_report matviews with cumulative summary queries TRT-2741: Phase 2 - Replace prow_test_report matviews with cumulative summary queries Jul 16, 2026
@mstaeble

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.


Your plan includes PR reviews subject to rate limits. More reviews will be available in 46 minutes.

… summary queries

Replace all four prow_test_report materialized views with direct queries
against the partitioned test_cumulative_summaries table from Phase 1.
This eliminates the expensive matview refresh cycle and reduces query
latency across all test report endpoints.

Key changes:
- New cumulative_query.go with core query builders (TestReportQuery,
  TestReportQueryCollapsed, UncollapsedTestReportWithStats) using 3-way
  prefix sum self-joins with partition-pruning date resolution
- Materialized CTE pipeline (filtered -> post_filtered -> stats) for
  uncollapsed /api/tests with processedFilterConditions push-down
- Aggregate-first approach for collapsed queries (per-date pre-aggregation
  then 3-way join of small results)
- SET LOCAL work_mem tuning per query path (4MB uncollapsed, 16MB collapsed)
  to enable parallel HashAggregates instead of sort-based plans
- Cross-variant statistics (AVG/STDDEV) computed in Go for the uncollapsed
  path, avoiding single-threaded WindowAgg on 1.8M rows
- Overall test summary computed from already-scanned results in Go
- Install/upgrade endpoints use precise name matching with UNION ALL for
  per-variant + "All" aggregate in a single query
- Feature gates rewritten with EXISTS-based lookup against partitioned table
- Remove matview cache, views.go, and PlatformInfraSuccess dead code

Performance (staging, release 4.19):
- /api/tests uncollapsed filtered: 55s -> 17s
- /api/tests collapsed: 14s -> 3.5s
- /api/install: 9.5s -> 0.56s
- /api/feature_gates: 8.2s -> 0.26s

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@mstaeble mstaeble force-pushed the worktree-trt-2741-phase2 branch from 65c172e to 8685ae5 Compare July 16, 2026 04:46

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (3)
pkg/dataloader/prowloader/prow.go (2)

1618-1622: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer structured logging for errors.

As per coding guidelines, prefer log.WithError(err) over formatting error strings manually.

♻️ Proposed refactor
 	suites, err := gcsJobRun.GetCombinedJUnitTestSuites(ctx)
 	if err != nil {
-		log.Warningf("failed to get junit test suites: %s", err.Error())
+		log.WithError(err).Warning("failed to get junit test suites")
 		return nil, 0, "", err
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/dataloader/prowloader/prow.go` around lines 1618 - 1622, Update the error
logging in the GetCombinedJUnitTestSuites failure path to use structured logging
via log.WithError(err) instead of interpolating err.Error() into the message,
while preserving the existing warning message and return behavior.

Source: Coding guidelines


749-769: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Ensure rows are closed on early exit.

It is idiomatic Go to defer rows.Close() immediately after checking the query error. If rows.Next() panics or a future code change returns early, defer rows.Close() prevents the connection from leaking.

♻️ Proposed refactor
 	rows, err := conn.Query(ctx, `
 		SELECT t.id FROM tmp_candidate_ids t
 		LEFT JOIN prow_job_runs r ON r.id = t.id
 		WHERE r.id IS NULL
 	`)
 	if err != nil {
 		return nil, fmt.Errorf("querying new job run IDs: %w", err)
 	}
+	defer rows.Close()
 	var newIDs []uint
 	for rows.Next() {
 		var id uint
 		if err := rows.Scan(&id); err != nil {
-			rows.Close()
 			return nil, fmt.Errorf("scanning new job run ID: %w", err)
 		}
 		newIDs = append(newIDs, id)
 	}
-	rows.Close()
 	if err := rows.Err(); err != nil {
 		return nil, fmt.Errorf("iterating new job run IDs: %w", err)
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/dataloader/prowloader/prow.go` around lines 749 - 769, In the
query-processing block, immediately defer rows.Close() after the successful
conn.Query call. Remove the manual rows.Close() calls, including the scan-error
path, while preserving the existing scan and rows.Err error handling.
pkg/api/tests.go (1)

492-496: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Wrap both transaction errors with operation context.

Returning the raw Exec and Scan errors makes failures difficult to distinguish. Wrap them with %w, identifying whether setting work_mem or scanning reports failed.

As per coding guidelines, “wrap errors with context using fmt.Errorf and %w.”

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

In `@pkg/api/tests.go` around lines 492 - 496, Update the transaction callback in
the database test flow to wrap both failures with operation-specific context
using fmt.Errorf and %w: identify errors from setting work_mem in the tx.Exec
call and errors from scanning testReports in the tx.Table(...).Scan call.
Preserve the underlying errors and transaction behavior.

Source: Coding guidelines

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

Inline comments:
In `@pkg/api/tests.go`:
- Around line 447-452: Update the filter splitting logic around
spec.Filter.Split so OR expressions spanning name, variants, and processed
fields are not applied as separate ANDed query layers. Preserve the complete
Boolean expression together, or translate it in a single query layer for both
collapsed and uncollapsed paths, while retaining independent pushdown only for
expressions whose semantics remain unchanged.
- Around line 523-557: Add table-driven tests targeting computeOverallTest, with
cases for empty input, zero current and previous runs, and mixed test reports.
Assert aggregated totals, all percentage fields, and improvement
values—including their signs—while using safePercent’s zero-denominator behavior
for zero-run cases.

In `@pkg/db/query/cumulative_query.go`:
- Around line 146-155: Update resolveDateRanges to return the Scan error from
the max-date lookup, wrapping it with release context instead of only logging
and returning. Propagate the returned error through every caller and query
builder so failures stop report construction rather than producing an empty
result; preserve normal date-range behavior when the lookup succeeds.
- Around line 218-247: Restrict processedFilterConditions in
pkg/db/query/cumulative_query.go:218-247 to an allowlist of fields available in
the filtered CTE, returning stats-derived fields such as working_average,
standard deviations, and delta_from_* in remaining for later filtering. Update
the pushdown expectations and coverage in pkg/db/query/test_queries.go:277-350
to include only pre-stats fields, and ensure
pkg/db/query/test_queries.go:383-398 leaves stats-derived filters for
application around the final result.
- Around line 331-339: The query builders do not consistently preserve
Filter.LinkOperator, causing default-AND filters and explicit-OR variant filters
to produce incorrect results. In pkg/db/query/cumulative_query.go:331-339,
default the name joiner to AND and switch only for explicit OR; at 181-204,
retain the variant filter’s operator with its conditions; and at 363-367, join
variant conditions using that operator. Apply equivalent behavior in
pkg/db/query/test_queries.go:265-276 for names and 328-332 for variants, then
add regression coverage for default-AND names and explicit-OR variants.

In `@pkg/db/query/test_queries.go`:
- Around line 249-250: Expand “CTE” on its first occurrence in the
UncollapsedTestReportWithStats comment to “common table expression (CTE)”, while
leaving the subsequent reference unchanged.

---

Nitpick comments:
In `@pkg/api/tests.go`:
- Around line 492-496: Update the transaction callback in the database test flow
to wrap both failures with operation-specific context using fmt.Errorf and %w:
identify errors from setting work_mem in the tx.Exec call and errors from
scanning testReports in the tx.Table(...).Scan call. Preserve the underlying
errors and transaction behavior.

In `@pkg/dataloader/prowloader/prow.go`:
- Around line 1618-1622: Update the error logging in the
GetCombinedJUnitTestSuites failure path to use structured logging via
log.WithError(err) instead of interpolating err.Error() into the message, while
preserving the existing warning message and return behavior.
- Around line 749-769: In the query-processing block, immediately defer
rows.Close() after the successful conn.Query call. Remove the manual
rows.Close() calls, including the scan-error path, while preserving the existing
scan and rows.Err error handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: a8bd26b8-90ae-46c2-9172-e1b8fb402697

📥 Commits

Reviewing files that changed from the base of the PR and between cc82cf3 and 8685ae5.

📒 Files selected for processing (15)
  • pkg/api/cache.go
  • pkg/api/cache_test.go
  • pkg/api/install.go
  • pkg/api/tests.go
  • pkg/dataloader/prowloader/prow.go
  • pkg/db/cumulativesummary/cumulative_summary.go
  • pkg/db/query/cumulative_query.go
  • pkg/db/query/cumulative_query_test.go
  • pkg/db/query/feature_gates.go
  • pkg/db/query/misc_queries.go
  • pkg/db/query/test_queries.go
  • pkg/db/views.go
  • pkg/flags/postgres_benchmarking_test.go
  • pkg/html/installhtml/util.go
  • pkg/sippyserver/server.go
💤 Files with no reviewable changes (4)
  • pkg/db/views.go
  • pkg/api/cache.go
  • pkg/db/query/misc_queries.go
  • pkg/api/cache_test.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • pkg/sippyserver/server.go
  • pkg/db/cumulativesummary/cumulative_summary.go
  • pkg/html/installhtml/util.go
  • pkg/db/query/feature_gates.go
  • pkg/flags/postgres_benchmarking_test.go

Comment thread pkg/api/tests.go
Comment on lines 447 to 452
var nameFilter, variantFilter, processedFilter *filter.Filter
if spec.Filter != nil {
var rawFilter *filter.Filter
rawFilter, processedFilter = spec.Filter.Split([]string{"name", "variants"})
nameFilter, variantFilter = rawFilter.Split([]string{"name"})
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Preserve OR semantics when pushing filters into separate query layers.

A filter such as name = X OR current_runs > 10 is split here, then applied as an inner name condition and an outer processed condition. The same problem affects name/variant OR combinations, silently narrowing results in both collapsed and uncollapsed paths. Keep cross-group OR expressions together or translate the complete Boolean expression in one query layer.

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

In `@pkg/api/tests.go` around lines 447 - 452, Update the filter splitting logic
around spec.Filter.Split so OR expressions spanning name, variants, and
processed fields are not applied as separate ANDed query layers. Preserve the
complete Boolean expression together, or translate it in a single query layer
for both collapsed and uncollapsed paths, while retaining independent pushdown
only for expressions whose semantics remain unchanged.

Comment thread pkg/api/tests.go
Comment on lines +523 to +557
func safePercent(numerator, denominator int) float64 {
if denominator == 0 {
return 0
}
return float64(numerator) * 100.0 / float64(denominator)
}

func computeOverallTest(testReports []apitype.Test) *apitype.Test {
overall := &apitype.Test{
ID: math.MaxInt32,
Name: "Overall",
}
for _, t := range testReports {
overall.CurrentRuns += t.CurrentRuns
overall.CurrentSuccesses += t.CurrentSuccesses
overall.CurrentFailures += t.CurrentFailures
overall.CurrentFlakes += t.CurrentFlakes
overall.PreviousRuns += t.PreviousRuns
overall.PreviousSuccesses += t.PreviousSuccesses
overall.PreviousFailures += t.PreviousFailures
overall.PreviousFlakes += t.PreviousFlakes
}
overall.CurrentPassPercentage = safePercent(overall.CurrentSuccesses, overall.CurrentRuns)
overall.CurrentFailurePercentage = safePercent(overall.CurrentFailures, overall.CurrentRuns)
overall.CurrentFlakePercentage = safePercent(overall.CurrentFlakes, overall.CurrentRuns)
overall.CurrentWorkingPercentage = safePercent(overall.CurrentSuccesses+overall.CurrentFlakes, overall.CurrentRuns)
overall.PreviousPassPercentage = safePercent(overall.PreviousSuccesses, overall.PreviousRuns)
overall.PreviousFailurePercentage = safePercent(overall.PreviousFailures, overall.PreviousRuns)
overall.PreviousFlakePercentage = safePercent(overall.PreviousFlakes, overall.PreviousRuns)
overall.PreviousWorkingPercentage = safePercent(overall.PreviousSuccesses+overall.PreviousFlakes, overall.PreviousRuns)
overall.NetFailureImprovement = overall.PreviousFailurePercentage - overall.CurrentFailurePercentage
overall.NetFlakeImprovement = overall.PreviousFlakePercentage - overall.CurrentFlakePercentage
overall.NetWorkingImprovement = overall.CurrentWorkingPercentage - overall.PreviousWorkingPercentage
overall.NetImprovement = overall.CurrentPassPercentage - overall.PreviousPassPercentage
return overall

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -C3 '\b(computeOverallTest|safePercent)\s*\(' pkg/api --glob '*_test.go'

Repository: openshift/sippy

Length of output: 153


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== pkg/api files ==\n'
git ls-files 'pkg/api/*' | sed -n '1,200p'

printf '\n== outline tests.go ==\n'
ast-grep outline pkg/api/tests.go --view expanded || true

printf '\n== relevant slice of tests.go ==\n'
sed -n '500,590p' pkg/api/tests.go

printf '\n== pkg/api test files mentioning Test / overall ==\n'
rg -n -C3 'Overall|computeOverallTest|safePercent|CurrentPassPercentage|NetFailureImprovement' pkg/api --glob '*_test.go' || true

Repository: openshift/sippy

Length of output: 25041


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== direct references to computeOverallTest ==\n'
rg -n 'computeOverallTest|safePercent' .

printf '\n== likely test coverage around tests.go ==\n'
rg -n -C3 'IncludeOverall|Overall"|\bOverall\b|NetImprovement|CurrentWorkingPercentage|PreviousWorkingPercentage' pkg/api --glob '*_test.go'

Repository: openshift/sippy

Length of output: 1467


Add table-driven tests for computeOverallTest in pkg/api/tests.go. Cover empty input, zero current/previous runs, and mixed reports so the totals, percentages, and improvement signs stay pinned down.

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

In `@pkg/api/tests.go` around lines 523 - 557, Add table-driven tests targeting
computeOverallTest, with cases for empty input, zero current and previous runs,
and mixed test reports. Assert aggregated totals, all percentage fields, and
improvement values—including their signs—while using safePercent’s
zero-denominator behavior for zero-run cases.

Source: Coding guidelines

Comment on lines +146 to +155
func resolveDateRanges(dbc *db.DB, release string, ranges ...*DateRange) {
var maxDate *civil.Date
row := dbc.DB.Table("test_cumulative_summaries").
Select("MAX(date)").
Where("release = ?", release).
Row()
if err := row.Scan(&maxDate); err != nil {
log.WithError(err).WithField("release", release).Error("failed to resolve max date for cumulative summaries")
return
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Propagate failures from the max-date lookup.

After Scan fails, query construction continues with unresolved future dates, so a transient lookup failure can become a successful but empty report. Return and wrap this error through the query builders instead of only logging it.

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

In `@pkg/db/query/cumulative_query.go` around lines 146 - 155, Update
resolveDateRanges to return the Scan error from the max-date lookup, wrapping it
with release context instead of only logging and returning. Propagate the
returned error through every caller and query builder so failures stop report
construction rather than producing an empty result; preserve normal date-range
behavior when the lookup succeeds.

Comment on lines +218 to +247
// processedFilterConditions converts arithmetic filter items to raw SQL WHERE
// conditions with parameterized args. Items with unsupported operators (ILIKE,
// array membership, etc.) are returned in the remaining filter for the caller to
// apply via GORM. Splitting is only safe for AND-linked filters; OR-linked
// filters are returned entirely as remaining.
func processedFilterConditions(f *filter.Filter) (conditions []string, args []any, remaining *filter.Filter) {
if f == nil || len(f.Items) == 0 {
return nil, nil, nil
}
if f.LinkOperator == filter.LinkOperatorOr {
return nil, nil, f
}
var unsupported []filter.FilterItem
for _, item := range f.Items {
if op, ok := arithmeticOps[item.Operator]; ok {
field := pq.QuoteIdentifier(item.Field)
cond := fmt.Sprintf("%s %s ?", field, op)
if item.Not {
cond = negateConditions([]string{cond})[0]
}
conditions = append(conditions, cond)
args = append(args, item.Value)
} else {
unsupported = append(unsupported, item)
}
}
if len(unsupported) > 0 {
remaining = &filter.Filter{Items: unsupported, LinkOperator: f.LinkOperator}
}
return conditions, args, remaining

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not push stats-only fields into post_filtered.

processedFilterConditions treats every arithmetic field as pushdown-safe. Fields such as working_average, standard deviations, and delta_from_* are created only by the final stats join, so default/AND filters on them produce missing-column SQL errors.

  • pkg/db/query/cumulative_query.go#L218-L247: allowlist fields available in filtered; return later-stage fields in remaining.
  • pkg/db/query/test_queries.go#L277-L350: push only fields available before the stats CTE.
  • pkg/db/query/test_queries.go#L383-L398: leave stats-derived filters for the caller to apply around this final result.
📍 Affects 2 files
  • pkg/db/query/cumulative_query.go#L218-L247 (this comment)
  • pkg/db/query/test_queries.go#L277-L350
  • pkg/db/query/test_queries.go#L383-L398
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/db/query/cumulative_query.go` around lines 218 - 247, Restrict
processedFilterConditions in pkg/db/query/cumulative_query.go:218-247 to an
allowlist of fields available in the filtered CTE, returning stats-derived
fields such as working_average, standard deviations, and delta_from_* in
remaining for later filtering. Update the pushdown expectations and coverage in
pkg/db/query/test_queries.go:277-350 to include only pre-stats fields, and
ensure pkg/db/query/test_queries.go:383-398 leaves stats-derived filters for
application around the final result.

Comment on lines +331 to +339
var nameJoinClause string
var nameJoinArgs []any
if len(nameConds) > 0 {
joiner := " OR "
if nameFilter.LinkOperator == filter.LinkOperatorAnd {
joiner = " AND "
}
nameJoinClause = "JOIN tests ON tests.id = tcs.test_id AND (" + strings.Join(nameConds, joiner) + ")"
nameJoinArgs = nameArgs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve Filter.LinkOperator when pushing filters down.

The filter contract defaults to AND unless LinkOperatorOr is explicit, but name conditions default to OR here while variant conditions are always combined with AND. Multi-item filters therefore return incorrect rows.

  • pkg/db/query/cumulative_query.go#L331-L339: default the name joiner to AND and switch only for explicit OR.
  • pkg/db/query/cumulative_query.go#L181-L204: preserve the variant filter’s link operator alongside its conditions.
  • pkg/db/query/cumulative_query.go#L363-L367: group variant conditions using that operator instead of appending each with AND.
  • pkg/db/query/test_queries.go#L265-L276: apply the same default-AND name behavior.
  • pkg/db/query/test_queries.go#L328-L332: combine variant conditions using the requested link operator.

Add regression cases for default-AND names and explicit-OR variants.

📍 Affects 2 files
  • pkg/db/query/cumulative_query.go#L331-L339 (this comment)
  • pkg/db/query/cumulative_query.go#L181-L204
  • pkg/db/query/cumulative_query.go#L363-L367
  • pkg/db/query/test_queries.go#L265-L276
  • pkg/db/query/test_queries.go#L328-L332
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/db/query/cumulative_query.go` around lines 331 - 339, The query builders
do not consistently preserve Filter.LinkOperator, causing default-AND filters
and explicit-OR variant filters to produce incorrect results. In
pkg/db/query/cumulative_query.go:331-339, default the name joiner to AND and
switch only for explicit OR; at 181-204, retain the variant filter’s operator
with its conditions; and at 363-367, join variant conditions using that
operator. Apply equivalent behavior in pkg/db/query/test_queries.go:265-276 for
names and 328-332 for variants, then add regression coverage for default-AND
names and explicit-OR variants.

Comment on lines +249 to +250
// UncollapsedTestReportWithStats builds a per-variant test report with cross-variant
// statistics using a materialized CTE pipeline: filtered -> post_filtered -> stats.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Expand CTE on first use.

Use “common table expression (CTE)” here.

As per path instructions, “Abbreviations like CTE, matview, etc. should be expanded on first use.”

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

In `@pkg/db/query/test_queries.go` around lines 249 - 250, Expand “CTE” on its
first occurrence in the UncollapsedTestReportWithStats comment to “common table
expression (CTE)”, while leaving the subsequent reference unchanged.

Source: Path instructions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. ready-for-human-review Indicates a PR has been reviewed by automated tools and is ready for human review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants