public double maxQueryGrowthRate(Duration window, Instant now) {
        if (snapshots.isEmpty()) return 0.1;
        // Find the period having the highest growth rate, where total growth exceeds 30% increase
        double maxGrowthRate = 0; // In query rate growth per second (to get good resolution)

        for (int start = 0; start < snapshots.size(); start++) {
            if (start > 0) { // Optimization: Skip this point when starting from the previous is better relative to the best rate so far
                Duration duration = durationBetween(start - 1, start);
                if (duration.toSeconds() != 0) {
                    double growthRate = (queryRateAt(start - 1) - queryRateAt(start)) / duration.toSeconds();
                    if (growthRate >= maxGrowthRate)
                        continue;
                }
            }
            // Find a subsequent snapshot where the query rate has increased significantly
            for (int end = start + 1; end < snapshots.size(); end++) {
                Duration duration = durationBetween(start, end);
                if (duration.toSeconds() == 0) continue;
                if (duration.compareTo(GROWTH_RATE_MIN_INTERVAL) < 0) continue; // Too short period to be considered
                if (significantGrowthBetween(start, end)) {
                    double growthRate = (queryRateAt(end) - queryRateAt(start)) / duration.toSeconds();
                    if (growthRate > maxGrowthRate)
                        maxGrowthRate = growthRate;
                }
            }
        }
        if (maxGrowthRate == 0) { // No periods of significant growth
            if (durationBetween(0, snapshots.size() - 1).toHours() < 24)
                return 0.1; //       ... because not much data
            else
                return 0.0; //       ... because load is stable
        }
        OptionalDouble queryRate = queryRate(window, now);
        if (queryRate.orElse(0) == 0) return 0.1; // Growth not expressible as a fraction of the current rate
        return maxGrowthRate * 60 / queryRate.getAsDouble();
    }
@Test
    public void test_real_data() {
        // Here we use real data from a production deployment, where significant query rate growth is measured over
        // a short period (ts0). This should not cause a significant difference in max growth rate compared to a node
        // measuring approximately the same growth
        Instant scaleAt = Instant.parse("2024-07-03T06:06:57Z");
        ClusterTimeseries ts0 = new ClusterTimeseries(cluster, readSnapshots("real-traffic-fast-growth"));
        double maxGrowthRate0 = ts0.maxQueryGrowthRate(Duration.ofMinutes(5), scaleAt);
        assertEquals(0.0896, maxGrowthRate0, delta);
        ClusterTimeseries ts1 = new ClusterTimeseries(cluster, readSnapshots("real-traffic-ordinary-growth"));
        double maxGrowthRate1 = ts1.maxQueryGrowthRate(Duration.ofMinutes(5), scaleAt);
        assertEquals(0.0733, maxGrowthRate1, delta);
        assertTrue(maxGrowthRate0 - maxGrowthRate1 < 0.1);
    }